Rex W. Douglass

Introduction

Library Loads

#libraries
library(lubridate)
library(tidyverse)

#devtools::install_github("ropensci/USAboundaries")
#devtools::install_github("ropensci/USAboundariesData")
library(USAboundaries) ; #install.packages('USAboundaries')
data(state_codes)

library(tidyverse)
library(scales)
library(gghighlight)
library(lubridate)
library(R0)  # consider moving all library commands to top -- this one was in a loop below

library(WikidataR)
library(countrycode)

library(usmap) ; # install.packages('usmap')
data(statepop)
#devtools::install_github("ropensci/USAboundaries")
#devtools::install_github("ropensci/USAboundariesData")
library(USAboundaries) ; #install.packages('USAboundaries')
data(state_codes)

library(tidyverse)
library(sf)

library(jsonlite)

#This is too slow it's downloading each
library(GADMTools)
library(strucchange) ; #install.packages('strucchange')
library(tsibble)

library(patchwork)

Data Loading and Cleaning


library(tsibble)

lhs_long <- readRDS("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/lhs_long.Rds")
#dim(lhs_long) #187,305

lhs_long_clean <- lhs_long %>% 
                  dplyr::select(dataset, gid,geonameid, wikidata_id ,date_asdate, confirmed, deaths, tested_people, tested_samples) %>%
                  group_by(dataset, gid,geonameid, wikidata_id ,date_asdate) %>% #if the same source has multiple values on the same thing on the same day, or different values across unmerged obs, then take the max
                  summarise_all(max, na.rm=T) %>% 
                  ungroup() %>%
                  mutate_if(is.numeric, list(~na_if(., -Inf))) %>%
                  mutate_if(is.numeric, list(~na_if(., Inf))) %>%
                  mutate(dataset_gid_geonameid_wikidata_id= paste(dataset,gid,geonameid, wikidata_id, sep="_")  ) %>%
                  mutate(gid_geonameid_wikidata_id= paste(gid,geonameid, wikidata_id, sep="_")  ) %>%
  
                  filter(!is.na(date_asdate)) %>%
                  
                  #First drop anything that's negative. Shouldn't be any negatives.
                  filter(is.na(confirmed) | confirmed>=0) %>%
                  filter(is.na(deaths) | deaths>=0) %>%
                  filter(is.na(tested_people) | tested_people>=0) %>%
                  filter(is.na(tested_samples) | tested_samples>=0) %>%
                  
                  #Then set 0s to NA, we don't trust NAs
                  mutate(confirmed=ifelse(confirmed==0, NA, confirmed)) %>%
                  mutate(deaths=ifelse(deaths==0, NA, deaths)) %>%
                  mutate(tested_people=ifelse(tested_people==0, NA, tested_people)) %>%
                  mutate(tested_samples=ifelse(tested_samples==0, NA, tested_samples)) %>%
                
                  #Then check first differences and drop anything that doesn't weakly increase monotonically
                  group_by(dataset, gid_geonameid_wikidata_id) %>% 
                    arrange(date_asdate) %>%
                    mutate(confirmed_cummax=confirmed %>% replace_na(0) %>% 
                             cummax(), deaths_cummax=deaths%>% replace_na(0) %>% cummax(), tested_people_cummax=tested_people%>% replace_na(0) %>% cummax(), 
                             tested_samples_cummax=tested_samples%>% replace_na(0) %>% cummax()) %>%
                  ungroup() %>%  
  
                  #About 4k of these observations show a decrease from one time step to the next which suggests either an original error or a joining error
                  #We're going to straight drop those observations as a cleaning step
                  #this isn't enough because if you have consecutive mistakes it'll show a positive fd even if it's not good enough
                  filter( (is.na(confirmed) | confirmed>=confirmed_cummax) &  #never allow for a reversal
                          (is.na(deaths) | deaths>=deaths_cummax) &        #never allow for a reversal
                          (is.na(tested_people) | tested_people>=tested_people_cummax) &  #never allow for a reversal
                          (is.na(tested_samples) | tested_samples>=tested_samples_cummax)  #never allow for a reversal
                          ) %>%
  #we're going to go one step further and require either confirmed or tested to be strictly higher
  #In words, during an episode we don't believe reports mean "no new cases" just no new good reporting
  #metabiota is the worst offender here so restricting it to just that
  filter( !(
            dataset=="metabiota" & #is metabiota
            (!is.na(confirmed) &   #with a non missing confirmed
              confirmed<=confirmed_cummax ) #that is equal to or less than the cumulative max until then.
            ) #reject these
          ) %>% #metabiota is really problematic 90% of what we're doing is trying to account for it
  
  #Also reject any where deaths are greater than confirmed
  filter(is.na(confirmed) | is.na(deaths) | confirmed>=deaths) %>%
  
  #also reject any where confirmed doesn't vary 
  group_by(gid ,  geonameid ,wikidata_id) %>% #chose not to do by dataset because testing datasets might not have confirmed
    filter(var(confirmed, na.rm=T)>0) %>%
  ungroup()

  
#dim(lhs_long_clean) #281,464 #292,580 #299213 #181,563

saveRDS(lhs_long_clean,
        "/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/lhs_long_cleand.Rds")

Summary Statistics of Our Data

print("Number of observations")
[1] "Number of observations"
dim(lhs_long_clean)
[1] 402845     15
print("Number of locations")
[1] "Number of locations"
lhs_long_clean$wikidata_id %>% unique() %>% length() #3,373
[1] 3895
print("Number of Days")
[1] "Number of Days"
lhs_long_clean$date_asdate %>% unique() %>% length() #113
[1] 126
library(DT) #https://rstudio.github.io/DT/
lhs_long_clean %>% count(dataset) %>% arrange(-n) %>% DT::datatable(options = list(pageLength = 20, autoWidth = TRUE))


#library(gt)
#lhs_long_clean %>% count(dataset) %>% arrange(-n) %>% gt() %>% 
# tab_header(
#    title = md("Location-Days by Dataset")#,
#    #subtitle = "Number of Days with Data by Dataset"
#  ) %>%
#  fmt_missing( columns=everything(), rows=NULL,missing_text = 0)

Spatial Variation in Data Availability

Country Level Data Availability


#gadm36 = st_read("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESSgadm/data_in/gadm36_gpkg/gadm36.gpkg")
#st_layers("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/gadm36_bycountry/gadm36_levels_gpkg/gadm36_levels.gpkg")
gadm36_levels_0 = st_read("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/gadm36_bycountry/gadm36_levels_gpkg/gadm36_levels.gpkg", layer="level0")  %>%
                  st_simplify(preserveTopology = FALSE, dTolerance =0.1) #  0.025 this is supposedly broken up by 6 levels and so should have u.s. 
#plot(gadm36_levels_0)
#dim(gadm36_levels_0_sf$sf)
#gadm_plot(gadm36_levels_0_sf)
lhs_long_place_sources <- lhs_long  %>% dplyr::select(gid,   geonameid, wikidata_id, dataset) %>% 
                           group_by(gid,  geonameid, wikidata_id) %>% count(dataset) %>%
                           group_by(gid,  geonameid, wikidata_id) %>%
                           summarise(datasets_n=n()) 

p0 <- gadm36_levels_0 %>% 
      left_join(lhs_long_place_sources %>% dplyr::select(gid=gid, datasets_n) %>%  left_join( gadm36_levels_0 %>% as.data.frame() %>% dplyr::select(gid=GID_0, NAME_0)  %>% distinct()  )
                ) %>%
      #replace_na(list(datasets_n = 0)) %>% 
      ggplot() + geom_sf(aes(fill = datasets_n)) +
      scale_fill_gradient(low="red", high="green") +
      theme_bw() 
p0 + ggtitle("Covid Count Data Availability at the Country Level")

temp <- gadm36_levels_0 %>%
   left_join(
   lhs_long  %>% count(gid, dataset) %>% rename(GID_0=gid) #there are still dupe geonames wikidata to gid matches that need to be fixed geonameid, wikidata_id, 
) 
Joining, by = "GID_0"
Column `GID_0` joining factor and character vector, coercing into character vector
temp_wide <- temp %>% as.data.frame() %>% dplyr::select(Country=NAME_0, dataset, n) %>% distinct() %>% pivot_wider( id_cols = Country, names_from = dataset,
  values_from = n, values_fill = NULL, values_fn = NULL) 

temp_wide %>% DT::datatable(options = list(pageLength = 20, autoWidth = TRUE))


#install.packages('gt')
#library(gt)
#temp_wide %>% gt() %>% 
# tab_header(
#    title = md("Data Availability by Country"),
#    subtitle = "Number of Days with Data by Dataset"
#  ) %>%
#  fmt_missing( columns=everything(), rows=NULL,missing_text = 0)

State/Province Level Data Availability

gadm36_levels_1 = st_read("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/gadm36_bycountry/gadm36_levels_gpkg/gadm36_levels.gpkg", layer="level1")  %>%
  st_simplify(preserveTopology = FALSE, dTolerance =0.1) #  0.025 this is supposedly broken up by 6 levels and so should have u.s. 
p1 <- gadm36_levels_1 %>% 
  left_join(lhs_long_place_sources %>% dplyr::select(gid=gid, datasets_n) %>%  left_join( gadm36_levels_1 %>% as.data.frame() %>% dplyr::select(gid=GID_1, NAME_1) %>% distinct()  )
  ) %>%
  #replace_na(list(datasets_n = 0)) %>% 
  ggplot() + geom_sf(aes(fill = datasets_n)) +
  scale_fill_gradient(low="red", high="green") +
  theme_bw() 
p1

temp <- gadm36_levels_1 %>%
   left_join(
   lhs_long  %>% count(gid, dataset) %>% rename(GID_1=gid) #there are still dupe geonames wikidata to gid matches that need to be fixed geonameid, wikidata_id, 
) 
Joining, by = "GID_1"
Column `GID_1` joining factor and character vector, coercing into character vector
temp_wide <- temp %>% as.data.frame() %>% dplyr::select(Country=NAME_0, Admin1=NAME_1, dataset, n) %>% distinct() %>% pivot_wider( id_cols = Country:Admin1, names_from = dataset,
  values_from = n, values_fill = NULL, values_fn = NULL) %>% mutate(total = rowSums(.[-c(1,2)], na.rm = T))

temp_wide %>% filter(total>0) %>% DT::datatable(options = list(pageLength = 10, autoWidth = TRUE))

NA

County District Level Data Availability

gadm36_levels_2 = st_read("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/gadm36_bycountry/gadm36_levels_gpkg/gadm36_levels.gpkg", layer="level2")  %>%
  st_simplify(preserveTopology = FALSE, dTolerance = 0.001) #  0.025 this is supposedly broken up by 6 levels and so should have u.s. I have to keep shrinking it so misisng goes to zero 
p2
temp <- gadm36_levels_2 %>%
   left_join(
   lhs_long  %>% count(gid, dataset) %>% rename(GID_2=gid) #there are still dupe geonames wikidata to gid matches that need to be fixed geonameid, wikidata_id, 
) 
Joining, by = "GID_2"
Column `GID_2` joining factor and character vector, coercing into character vector
temp_wide <- temp %>% as.data.frame() %>% dplyr::select(Country=NAME_0, Admin1=NAME_1, Admin2=NAME_2, dataset, n) %>% distinct() %>% pivot_wider( id_cols = Country:Admin2, names_from = dataset,
  values_from = n, values_fill = NULL, values_fn = NULL) %>% mutate(total = rowSums(.[-c(1,2,3)], na.rm = T))

temp_wide %>% filter(total>0) %>% DT::datatable(options = list(pageLength = 10, autoWidth = TRUE))
It seems your data is too big for client-side DataTables. You may consider server-side processing: https://rstudio.github.io/DT/server.htmlIt seems your data is too big for client-side DataTables. You may consider server-side processing: https://rstudio.github.io/DT/server.html

Country Data Availability of Testing


lhs_long_place_sources_testing <- lhs_long  %>%
                                  dplyr::select(gid,  geonameid, wikidata_id, date_asdate, confirmed, tested_people, tested_samples) %>%
                                  group_by(gid,  geonameid, wikidata_id, date_asdate) %>% 
                                  mutate_if(is.numeric, max, na.rm=T) %>%
                                  filter(!duplicated(date_asdate)) %>%
                                  ungroup() %>%
                                  mutate_if(is.numeric, list(~na_if(., -Inf))) %>%
                                  mutate_if(is.numeric, list(~na_if(., Inf))) %>%
                                  mutate(percent_of_days_without_testing=!is.na(date_asdate) & (is.na(tested_people) & is.na(tested_samples)  )) %>%
                                  
                                  group_by(gid,  geonameid, wikidata_id) %>% 
                                  summarise(
                                            percent_of_days_without_testing=sum(percent_of_days_without_testing, na.rm=T)/n()
                                            ) %>%
                                  mutate(percent_of_days_with_testing= 1-percent_of_days_without_testing) 
`mutate_if()` ignored the following grouping variables:
Columns `gid`, `geonameid`, `wikidata_id`, `date_asdate`
p0_testing <- gadm36_levels_0 %>% 
      left_join(lhs_long_place_sources_testing %>% dplyr::select(gid=gid, percent_of_days_with_testing) %>%  left_join( gadm36_levels_0 %>% as.data.frame() %>% dplyr::select(gid=GID_0, NAME_0)  %>% distinct()  )
                ) %>%
      #replace_na(list(datasets_n = 0)) %>% 
      ggplot() + geom_sf(aes(fill = percent_of_days_with_testing)) +
      scale_fill_gradient(low="red", high="green") +
      theme_bw() + ggtitle("Percent of Days with Testing counts")
Adding missing grouping variables: `geonameid`
Joining, by = "gid"
Column `gid` joining character vector and factor, coercing into character vectorJoining, by = "NAME_0"
p0_testing

p1_testing <- gadm36_levels_1 %>% 
  left_join(lhs_long_place_sources_testing %>% dplyr::select(gid=gid, percent_of_days_with_testing) %>%  left_join( gadm36_levels_1 %>% as.data.frame() %>% dplyr::select(gid=GID_1, NAME_1) %>% distinct()  )
  ) %>%
  #replace_na(list(datasets_n = 0)) %>% 
  ggplot() + geom_sf(aes(fill = percent_of_days_with_testing)) +
  scale_fill_gradient(low="red", high="green") +
  theme_bw()  + ggtitle("Percent of Days with Testing counts")
p1_testing

Data Availability and Interpolation over Time


#test <- lhs_long %>% group_by(dataset, gid, geonameid, wikidata_id, date_asdate) %>% summarize(n=n())

all_na <- function(x) any(!is.na(x)) #https://intellipaat.com/community/12999/remove-columns-from-dataframe-where-all-values-are-na

#bing looks off by a day from the other ones
lhs_wide_qcode <- lhs_long %>% 
                  filter(!is.na(wikidata_id) & !is.na(date_asdate)) %>%
                  group_by(gid, geonameid, wikidata_id, date_asdate) %>%  mutate(confirmed_var=var(confirmed, na.rm=T), deaths_var=var(deaths, na.rm=T)) %>% ungroup() %>%
                  dplyr::select(dataset, gid, geonameid, wikidata_id, date_asdate,confirmed, deaths, tested_samples, tested_people) %>%
                  group_by(dataset, gid, geonameid, wikidata_id, date_asdate) %>%  summarise_if(is.numeric,max,na.rm=T) %>% ungroup() %>% #this is a hack, we should have dupes within datasets
                  pivot_wider(names_from = dataset, values_from = c(confirmed, deaths, tested_samples, tested_people) ) %>% 
                  mutate_if(is.numeric, list(~na_if(abs(.), Inf))) %>% #https://stackoverflow.com/questions/12188509/cleaning-inf-values-from-an-r-dataframe
                  select_if(all_na) 

dim(lhs_wide_qcode) #82,157 82k place/day observations
length(unique(lhs_wide_qcode$wikidata_id)) #3697 #almost 4k 
test <- lhs_wide_qcode %>% dplyr::select(starts_with("confirmed")) %>% distinct() 
#cor(test, use="pairwise.complete.obs")

lhs_long_median <- lhs_long %>% group_by(gid, geonameid, wikidata_id, date_asdate) %>% summarize_if(is.numeric, median, na.rm=T) %>% dplyr::select(-ends_with("_fd")) %>% #we take the median across observations
                   mutate(CFR=deaths/confirmed)
#dim(lhs_long_median)
#summary(lhs_long_median)

Here we do the actual interpolation. For each individual location-dataset, we fit a piecewise linear model over time, and then use that to average over day to day noise and interpolate between observations. Because this is in log space, the slope of that line is the day on day percent increase in the count. We finish by fitting a piecewise intercept model to those slopes to get a single daily estimate of how much the count is increasing. Datasets are able to disagree in lots of different ways and we still recover a correct rate of change.

Interpolation of Counts

To each individual dataset-location series, we fit a piecewise linear trend. Each segment is required to have at least 3 observations, but otherwise we make no other constraints. This allows us to flexibly fit linear segments as well as tight curves. We also allow for structural breaks where the series stops, has a structural shift up or down because say a change in reporting rules, but other then otherwise continues as normal. We take the linear trend fit as our best estimate at each point. This averages over day to day noise, e.g. under reporting on the weekend. It also allows us to interpolate between observations where there is missingness in the series but we have reasonable beliefs the true measure continued linearly between the observed points.


dataset_places <- lhs_long_clean %>% dplyr::select(dataset_gid_geonameid_wikidata_id) %>% distinct() %>% pull(dataset_gid_geonameid_wikidata_id)
library(party)
temp_list1 <- list()
for(q in dataset_places  ){
      try({
        temp <- NULL
        temp <- lhs_long_clean %>%
                filter(dataset_gid_geonameid_wikidata_id %in% q) %>%
                arrange(date_asdate) %>%

                mutate(confirmed_log=log(confirmed)) %>%
                mutate(deaths_log=log(deaths)) %>%
                mutate(tested_people_log=log(tested_people)) %>%
                mutate(tested_samples_log=log(tested_samples)) 
          
        if(nrow(temp)==0){next()}
        
        temp <- temp %>% expand(dataset, gid_geonameid_wikidata_id, gid, geonameid,wikidata_id, date_asdate=min(date_asdate):max(date_asdate) %>% as_date() ) %>% 
                 full_join(temp) %>% 
                 mutate(date_asnumeric= as.numeric(date_asdate) ) %>% 
                 arrange(date_asnumeric) %>%
                 mutate(confirmed_nonmissing_count     = (!is.na(confirmed)) %>% cumsum() ) %>%
                 mutate(deaths_nonmissing_count     = (!is.na(deaths)) %>% cumsum() ) %>%
                 mutate(tested_people_nonmissing_count     = (!is.na(tested_people)) %>% cumsum() ) %>%
                 mutate(tested_samples_nonmissing_count     = (!is.na(tested_samples)) %>% cumsum() ) %>%
        
                 arrange(-date_asnumeric) %>%
                 mutate(confirmed_nonmissing_count_reversed     = (!is.na(confirmed)) %>% cumsum() ) %>%
                 mutate(deaths_nonmissing_count_reversed     = (!is.na(deaths)) %>% cumsum() ) %>%
                 mutate(tested_people_nonmissing_count_reversed     = (!is.na(tested_people)) %>% cumsum() ) %>%
                 mutate(tested_samples_nonmissing_count_reversed     = (!is.na(tested_samples)) %>% cumsum() ) %>% 
                 arrange(date_asdate) 

        tryCatch({  
          if(sum(!is.na(temp$confirmed_log))>=3){ #need at least 3 points
            tree_confirmed <- party::mob(confirmed_log ~ 1 + date_asnumeric    | date_asnumeric , control = mob_control(minsplit = 3, alpha=.2), data = temp,  model = linearModel)  # + I(date_asnumeric^2)  
            temp$confirmed_log_y_hat <- predict( tree_confirmed, newdata=temp , type = c("response") )
            temp$confirmed_log_group_number <-  predict( tree_confirmed, newdata=temp , type = c("node"))
            temp <- temp %>% 
                    mutate(confirmed_log_y_hat       =ifelse(confirmed_nonmissing_count>0 & confirmed_nonmissing_count_reversed>0,confirmed_log_y_hat,NA)) %>% #only interpolate within the observed data, never before or after
                    mutate(confirmed_log_group_number=ifelse(confirmed_nonmissing_count>0 & confirmed_nonmissing_count_reversed>0,confirmed_log_group_number,NA)) %>% #only interpolate within the observed data, never before or after

                    group_by(confirmed_log_group_number) %>%
                    arrange(date_asnumeric) %>%
                    mutate(confirmed_log_y_hat_slope=tsibble::difference(confirmed_log_y_hat)) %>% 
                    fill(confirmed_log_y_hat_slope, .direction="up") %>% 
                    ungroup() %>%
                    mutate(confirmed_log_y_hat_percent_change = round((exp(confirmed_log_y_hat_slope)-1)*100,2))  %>%
                    mutate(confirmed_log_y_hat=ifelse(confirmed_log_y_hat<0,NA, confirmed_log_y_hat))
          }
        }, error = function(e) {})
        
        tryCatch({  
          if(sum(!is.na(temp$deaths_log))>=3){ #need at least 3 points
            tree_deaths <- party::mob(deaths_log ~ 1 + date_asnumeric    | date_asnumeric , control = mob_control(minsplit = 3, alpha=.2), data = temp,  model = linearModel)  # + I(date_asnumeric^2)    
            temp$deaths_log_y_hat <- predict( tree_deaths, newdata=temp , type = c("response") )
            temp$deaths_log_group_number <-  predict( tree_deaths, newdata=temp , type = c("node"))
            temp <- temp %>% 
                    mutate(deaths_log_y_hat=ifelse(deaths_nonmissing_count>0 & deaths_nonmissing_count_reversed>0,deaths_log_y_hat,NA)) %>% #only interpolate within the observed data, never before
                    mutate(deaths_log_group_number=ifelse(deaths_nonmissing_count>0 & deaths_nonmissing_count_reversed>0,deaths_log_group_number,NA)) %>% #only interpolate within the observed data, never before

                    group_by(deaths_log_group_number) %>% 
                    arrange(date_asnumeric) %>% 
                    mutate(deaths_log_y_hat_slope=tsibble::difference(deaths_log_y_hat)) %>%
                    fill(deaths_log_y_hat_slope, .direction="up") %>%
                    ungroup() %>%
                    mutate(deaths_log_y_hat_percent_change = round((exp(deaths_log_y_hat_slope)-1)*100,2)) %>%
                    mutate(deaths_log_y_hat=ifelse(deaths_log_y_hat<0,NA, deaths_log_y_hat)) #reject any where the prediction is less than 1 full case
          }
        }, error = function(e) {})
        
        tryCatch({  
          if(sum(!is.na(temp$tested_people_log))>=3){ #need at least 3 points
            tree_tested_people <- party::mob(tested_people_log ~ 1 + date_asnumeric    | date_asnumeric , control = mob_control(minsplit = 3, alpha=.2), data = temp,  model = linearModel)  # + I(date_asnumeric^2)   
            temp$tested_people_log_y_hat <- predict( tree_tested_people, newdata=temp , type = c("response") )
            temp$tested_people_log_group_number <-  predict( tree_tested_people, newdata=temp , type = c("node"))
            temp <- temp %>% 
                       mutate(tested_people_log_y_hat=ifelse(tested_people_nonmissing_count>0 & tested_people_nonmissing_count_reversed>0,tested_people_log_y_hat,NA)) %>% #only interpolate within the observed data, never before
                       mutate(tested_people_log_group_number=ifelse(tested_people_nonmissing_count>0 & tested_people_nonmissing_count_reversed>0,tested_people_log_group_number,NA)) %>% #only interpolate within the observed data, never before
              
                       group_by(tested_people_log_group_number) %>% 
                       arrange(date_asnumeric) %>%
                       mutate(tested_people_log_y_hat_slope=tsibble::difference(tested_people_log_y_hat)) %>% 
                       fill(tested_people_log_y_hat_slope, .direction="up") %>% ungroup() %>%
                       mutate(tested_people_log_y_hat_percent_change = round((exp(tested_people_log_y_hat_slope)-1)*100,2)) %>%
                       mutate(tested_people_log_y_hat=ifelse(tested_people_log_y_hat<0,NA, tested_people_log_y_hat)) #reject any where the prediction is less than 1 full case
          }
        }, error = function(e) {})
        
        temp_list1[[q ]] <- temp
  
      })
}
lhs_long_clean_imputed1 <- bind_rows(temp_list1)
dim(lhs_long_clean_imputed1) #500,786 #bigger because we're interpolating now

#rt1 <- rpart(formula = confirmed_log_y_hat_percent_change ~ date_asnumeric, data=test)
#interpolated = data.frame(date_asnumeric=min(test$date_asnumeric):max(test$date_asnumeric) )
#interpolated$confirmed_log_y_hat_percent_change_y_hat <-  predict(rt1, newdata=interpolated)
#interpolated$date_asdate <- as.Date(interpolated$date_asnumeric)

places <- lhs_long_clean %>% dplyr::select(gid_geonameid_wikidata_id) %>% distinct() %>% pull(gid_geonameid_wikidata_id)

library(rpart)
minsplit=6
minbucket=3
temp_list2 <- list()
for(q in places ){
  print(q)
  temp <- lhs_long_clean_imputed1 %>% 
                 filter(gid_geonameid_wikidata_id %in% q) %>% 
                 arrange(date_asnumeric) 
    
          
  tryCatch({  
    rt1 <- rpart::rpart(formula = confirmed_log_y_hat_percent_change ~ date_asnumeric,
                        data=temp %>% filter(!is.na(confirmed_log)), #to keep from fitting to interpolate slopes that are out of domain and usually wrong, require confirmed to not be missing or na
                        control = rpart.control(minsplit = minsplit, minbucket=minbucket))
    temp$confirmed_log_y_hat_percent_change_y_hat <-  predict(rt1, newdata=temp) #this prediction helpfully tries to impute backwards even before there are any day in any series
    #We need to nuke it if no data exist
    temp <- temp %>%
            group_by(date_asdate) %>%
            mutate( confirmed_nonmissing_count_datasets=sum(confirmed_nonmissing_count>0,na.rm=T) ) %>%
            mutate( confirmed_nonmissing_count_datasets_reversed=sum(confirmed_nonmissing_count_reversed>0,na.rm=T) ) %>%
            mutate(confirmed_log_y_hat_percent_change_y_hat=ifelse(confirmed_nonmissing_count_datasets>0 & confirmed_nonmissing_count_datasets_reversed>0,confirmed_log_y_hat_percent_change_y_hat,NA))  %>%
      ungroup()
    
  }, error = function(e) {})
  
  tryCatch({  
    rt2 <- rpart::rpart(formula = deaths_log_y_hat_percent_change ~ date_asnumeric,
                        data=temp %>% filter(!is.na(deaths_log)),
                        control = rpart.control(minsplit = minsplit, minbucket=minbucket))
    temp$deaths_log_y_hat_percent_change_y_hat <-  predict(rt2, newdata=temp)
    temp <- temp %>%
        group_by(date_asdate) %>%
        mutate( deaths_nonmissing_count_datasets=sum(deaths_nonmissing_count>0,na.rm=T) ) %>%
        mutate( deaths_nonmissing_count_datasets_reversed=sum(deaths_nonmissing_count_reversed>0,na.rm=T) ) %>%
        mutate(deaths_log_y_hat_percent_change_y_hat=ifelse(deaths_nonmissing_count_datasets>0 & deaths_nonmissing_count_datasets_reversed>0,deaths_log_y_hat_percent_change_y_hat,NA)) %>%
      ungroup()
        
  }, error = function(e) {})

  tryCatch({  
    rt3 <- rpart::rpart(formula = tested_people_log_y_hat_percent_change ~ date_asnumeric,
                    data=temp %>% filter(!is.na(tested_people_log)),
                    control = rpart.control(minsplit = minsplit, minbucket=minbucket))
    temp$tested_people_log_y_hat_percent_change_y_hat <-  predict(rt3, newdata=temp, control = rpart.control(minsplit = minsplit, minbucket=minbucket))
    temp <- temp %>%
        group_by(date_asdate) %>%
        mutate( tested_people_nonmissing_count_datasets=sum(tested_people_nonmissing_count>0,na.rm=T) ) %>%
        mutate( tested_people_nonmissing_count_datasets_reversed=sum(tested_people_nonmissing_count_reversed>0,na.rm=T) ) %>%
      
        mutate(tested_people_log_y_hat_percent_change_y_hat=ifelse(tested_people_nonmissing_count_datasets>0 & tested_people_nonmissing_count_datasets_reversed>0,tested_people_log_y_hat_percent_change_y_hat,NA))  %>%
      ungroup()
  }, error = function(e) {})
  
  temp_list2[[q ]] <- temp
}
lhs_long_clean_imputed2 <- bind_rows(temp_list2)

lhs_long_clean_imputed <- lhs_long_clean_imputed2
dim(lhs_long_clean_imputed) #419910 #413475 #408,369 #we lose anywithout q codes here
saveRDS(lhs_long_clean_imputed, "/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/lhs_long_clean_imputed.Rds")

Examples

China

#China
#"Q148"

test <- lhs_long_clean_imputed %>% 
        mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q148") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation0 <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("China Q148 Confirmed") + facet_wrap(~dataset   )

Data on China shows variation across datasets for when they start measuring. Only two observe the very beginning of the outbreak. All of the datasets show a discontinuity where reporting standards must have changed. Our method attempts to bridge that gap in 3 of the series but not two others.

p_interpolation0

Italy

#Italy
#"Q38"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q38") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation1 <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Italy Q38 Confirmed") + facet_wrap(~dataset   )

Italy likewise shows variation in the start of recording across datasets. There’s also variation in the initial sparcity. Wikipedia is strangely missing data in the middle. Our method linearly interpolates into that space in a way in a way we probably don’t want.

p_interpolation1

Italy

#US
#"Q30"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q30") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation2 <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("US Q30 Confirmed") + facet_wrap(~dataset   )
p_interpolation2

New York State

#US
#"Q30"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q1384") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation3 <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("New York State Q1384 Confirmed") + facet_wrap(~dataset   )
p_interpolation3

New York City (by county)

nyt has it just by city, it doesn’t break it down by the boroughs. But because gadm doesn’t do cities we don’t assign it a qcode.

usafacts has it as New York County which is New York County (Manhattan)

#Brooklyn (Q18419)
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q855974") %>%  #no hits?
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation4a <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Bronx County (Q855974)") + facet_wrap(~dataset   ) + guides( color = FALSE)

#Queens County, New York Q5142559
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q5142559") %>%  #no hits?
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation4b <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Queens County, New York Q5142559") + facet_wrap(~dataset   ) + guides( color = FALSE)

#Brooklyn is aparently Kings County Q11980692
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q11980692") %>%  #no hits?
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation4c <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Brooklyn is Kings County Q11980692") + facet_wrap(~dataset   ) + guides( color = FALSE)

# Manhattan is New York County Q500416
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q500416") %>%  #no hits?
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation4d <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Manhattan is New York County Q500416") + facet_wrap(~dataset   ) + guides( color = FALSE)

#Staten Island is richmond county Q11997784
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q11997784") %>%  #no hits?
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )

p_interpolation4e <- test %>%
                    ggplot() + 
                       geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                       geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                       #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                       theme_bw() +
                       ggtitle("Staten Island  Richmond County Q11997784") + facet_wrap(~dataset   ) + guides( color = FALSE)

Note that CSSE is conflating all of New York City with Manhattan/New York County, Bing is too I think

p_interpolation4a + p_interpolation4b + p_interpolation4c + p_interpolation4d + p_interpolation4e

Plots by Countries

library(data.table)
geonames <- fread("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/allCountries.txt", sep="\t") %>% mutate_if(is.numeric,as.character) %>% mutate_if(is.factor,as.character)
|--------------------------------------------------|
|==================================================|
|--------------------------------------------------|
|==================================================|
Found and resolved improper quoting out-of-sample. First healed line 522433: <<8436127  "Baki-Pilsen" Brewery   "Baki-Pilsen" Brewery       40.32864    49.78044    P   PPLL    AZ                      0       -25 Asia/Baku   2012-12-17>>. If the fields are not quoted (e.g. field separator does not appear within any field), try quote="" to avoid this warning.
dim(geonames) #12,006,426
[1] 12006426       19
geonames_small <- geonames %>% dplyr::select(geonameid=V1, name_text=V2) %>% inner_join( lhs_long_clean_imputed %>% dplyr::select(geonameid) %>% distinct() )
Joining, by = "geonameid"
dim(geonames_small)
[1] 3920    2

Confirmed

p_confirmed_by_country <- lhs_long_clean_imputed %>%
                          filter(!gid %>% str_detect("_") ) %>%
                          left_join(geonames_small  ) %>% mutate(name_text %>% as.factor()) %>%
                          mutate(group=paste(gid_geonameid_wikidata_id,confirmed_log_group_number)) %>%
                          ggplot() + 
                             #geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
                             geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
                             #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                             theme_bw() +
                             ggtitle("Confirmed (log) by Country") + facet_wrap(~name_text   ) + guides( color = FALSE) +
                            theme(
                              strip.background = element_blank()
                            ,  strip.text.x = element_blank()
                            )
p_confirmed_by_country

Deaths

p_deaths_by_country <- lhs_long_clean_imputed %>%
                          filter(!gid %>% str_detect("_") ) %>%
                          left_join(geonames_small  ) %>% mutate(name_text %>% as.factor()) %>%
                          mutate(group=paste(gid_geonameid_wikidata_id,confirmed_log_group_number)) %>%
                          ggplot() + 
                             #geom_point( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset), alpha=.3) +
                             geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
                             #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                             theme_bw() +
                             ggtitle("Deaths (log) by Country") + facet_wrap(~name_text   ) + guides( color = FALSE) +
                            theme(
                              strip.background = element_blank()
                            ,  strip.text.x = element_blank()
                            )
p_deaths_by_country

Tests

p_tested_people_by_country <- lhs_long_clean_imputed %>%
                          filter(!gid %>% str_detect("_") ) %>%
                          left_join(geonames_small  ) %>% mutate(name_text %>% as.factor()) %>%
                          mutate(group=paste(gid_geonameid_wikidata_id,confirmed_log_group_number)) %>%
                          ggplot() + 
                             #geom_point( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset), alpha=.3) +
                             geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
                             #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
                             theme_bw() +
                             ggtitle("Tests (log) by Country") + facet_wrap(~name_text   ) + guides( color = FALSE) +
                            theme(
                              strip.background = element_blank()
                            ,  strip.text.x = element_blank()
                            )
p_tested_people_by_country

Interpolation of Rate of Change

Plot Confirmed Curves for Select Locations


library(patchwork)
lhs_long_clean_imputed <- readRDS( "/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/lhs_long_clean_imputed.Rds")
dim(lhs_long_clean_imputed) #45,609 #337043
#we want the colors to be consistent by dataset too btw

#####
#USA Q30

#bp_temp <- breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=temp_df %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q30"))
#confirmed_log_y_hat_percent_change=fitted.values(bp_temp)

test <- lhs_long_clean_imputed %>%
        mutate(group=paste(dataset,wikidata_id,confirmed_log_group_number)) %>%
        filter(wikidata_id=="Q30") %>% 
        arrange(date_asdate)  %>%
        mutate(date_asnumeric = date_asdate %>% as.numeric() )

#rt1 <- rpart(formula = confirmed_log_y_hat_percent_change ~ date_asnumeric, data=test)
#interpolated = data.frame(date_asnumeric=min(test$date_asnumeric):max(test$date_asnumeric) )
#interpolated$confirmed_log_y_hat_percent_change_y_hat <-  predict(rt1, newdata=interpolated)
#interpolated$date_asdate <- as.Date(interpolated$date_asnumeric)

p0a <- test %>%
        ggplot() + 
           geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
           geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
           #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
           theme_bw() +
           ggtitle("USA Q30 Confirmed") # + facet_wrap(~dataset) 

p0b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3 ) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black"  ) +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("USA Q30 Confirmed") # + facet_wrap(~dataset)+ ylab("Daily Percent Change Confirmed")

#p0a / p0b



#####
#China Q148

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_group_number)) %>% filter(wikidata_id=="Q148") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%

p1a <- test %>% 
ggplot() + 
   geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("China Q148 Confirmed")

p1b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("China Q148 Confirmed")+ ylab("Daily Percent Change Confirmed")
   

#p1a / p1b

#India
#"Q668"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q668") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p2a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("India Q668 Confirmed")

p2b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("India Q668 Confirmed")+ ylab("Daily Percent Change Confirmed")
 
  
#p2a / p2b



#Italy
#"Q38"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q38") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p4a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("Italy Q38 Confirmed")

p4b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Italy Q38 Confirmed")+ ylab("Daily Percent Change Confirmed")
   
    
#p4a / p4b



#South Korea
#"Q884"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q884") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p5a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("South Korea Q884  Confirmed")

p5b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("South Korea Q884 Confirmed") + ylab("Daily Percent Change Confirmed")
   
    
#p5a / p5b
(p0a + p1a + p2a ) / (p0b + p1b + p2b )

( p4a + p5a) / ( p4b + p5b)



test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q1439") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p0a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Texas Q1439 Confirmed")

p0b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Texas Q1439 Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")

#Bexar
#"Q16861"
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q16861") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )
p1a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Bexar County Q16861 Confirmed")
p1b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Bexar County Q16861 Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")

#California
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q99") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )
p2a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("California Q99 Confirmed")
p2b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("California Q99 Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")

#San Diego County (Q108143)
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q108143") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )
p3a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("San Diego County (Q108143) Confirmed")
p3b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("San Diego County (Q108143) Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")

#Florida (Q812)
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q812") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )
p4a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Florida (Q812) Confirmed")
p4b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Florida (Q812) Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")


#St. Lucie County (Q494564)
test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,confirmed_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q494564") %>% 
        mutate(group=paste(dataset, wikidata_id,confirmed_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( confirmed_log_y_hat_percent_change = breakpoints(formula=confirmed_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )
p5a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=confirmed_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("St. Lucie County (Q494564) Confirmed")
p5b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=confirmed_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=confirmed_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=confirmed_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("St. Lucie County (Q494564) Confirmed") + ylim(0,100)+ ylab("Daily Percent Change Confirmed")
#Not counting slopes that were interpolated out of domain fixed california's plot
( p0a + p1a ) / ( p0b + p1b )

( p2a + p3a ) / ( p2b + p3b )

( p4a + p5a) / ( p4b + p5b)

Plot Death Curves for Select Locations

Show how interpolation works on deaths


test <- lhs_long_clean_imputed %>%
        mutate(group=paste(dataset,wikidata_id,deaths_log_group_number)) %>%
        filter(wikidata_id=="Q30") %>% 
        arrange(date_asdate)  %>%
        mutate(date_asnumeric = date_asdate %>% as.numeric() )

p0a <- test %>%
        ggplot() + 
           geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
           geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
           #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
           theme_bw() +
           ggtitle("USA Q30 Deaths") # + facet_wrap(~dataset) 

p0b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3 ) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black"  ) +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("USA Q30 Deaths") + ylab("Daily Percent Change Deaths") # + facet_wrap(~dataset)

#p0a / p0b


#####
#China Q148

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,deaths_log_group_number)) %>% filter(wikidata_id=="Q148") %>% 
        mutate(group=paste(dataset, wikidata_id,deaths_log_group_number)) %>%
        arrange(date_asdate) #%>%

p1a <- test %>% 
ggplot() + 
   geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("China Q148 Deaths")

p1b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("China Q148 Deaths")+ ylab("Daily Percent Change Deaths")
   

#p1a / p1b

#India
#"Q668"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,deaths_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q668") %>% 
        mutate(group=paste(dataset, wikidata_id,deaths_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( deaths_log_y_hat_percent_change = breakpoints(formula=deaths_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p2a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("India Q668 Deaths")

p2b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("India Q668 Deaths")+ ylab("Daily Percent Change Deaths")
 
  
#p2a / p2b

#Bexar
#"Q16861"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,deaths_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q16861") %>% 
        mutate(group=paste(dataset, wikidata_id,deaths_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( deaths_log_y_hat_percent_change = breakpoints(formula=deaths_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p3a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Bexar County Q16861 Deaths")

p3b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Bexar County Q16861 Deaths") + ylim(0,100)+ ylab("Daily Percent Change Deaths")
   
#p3a / p3b



#Italy
#"Q38"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,deaths_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q38") %>% 
        mutate(group=paste(dataset, wikidata_id,deaths_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( deaths_log_y_hat_percent_change = breakpoints(formula=deaths_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p4a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("Italy Q38 Deaths")

p4b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Italy Q38 Deaths")+ ylab("Daily Percent Change Deaths")
   
    
#p4a / p4b



#South Korea
#"Q884"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,deaths_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q884") %>% 
        mutate(group=paste(dataset, wikidata_id,deaths_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( deaths_log_y_hat_percent_change = breakpoints(formula=deaths_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p5a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=deaths_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("South Korea Q884  Deaths")

p5b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=deaths_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=deaths_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=deaths_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=deaths_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("South Korea Q884 Deaths") + ylab("Daily Percent Change Deaths")
   
    
#p5a / p5b

I need to fix this, USA has a fraction of a death

Note the discontinuity in Chin when they added those 1k deaths to the total

India deaths is broken, we shouldn’t be interpolating a rate before we think the number is greater than 0

(p0a + p1a + p2a ) / (p0b + p1b + p2b )

(p3a + p4a + p5a) / (p3b + p4b + p5b)

Plot Testing Curves for Select Locations

Show how interpolation works on tested

US is an example where we interpolated past our available data. Shouldn’t do that either!


test <- lhs_long_clean_imputed %>%
        mutate(group=paste(dataset,wikidata_id,tested_people_log_group_number)) %>%
        filter(wikidata_id=="Q30") %>% 
        arrange(date_asdate)  %>%
        mutate(date_asnumeric = date_asdate %>% as.numeric() )

p0a <- test %>%
        ggplot() + 
           geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
           geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
           #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
           theme_bw() +
           ggtitle("USA Q30 Tested")  #+ facet_wrap(~dataset) 

p0b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3 ) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black"  ) +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("USA Q30 tested_people") + ylab("Daily Percent Change tested_people") # + facet_wrap(~dataset)

#p0a / p0b


#####
#China Q148

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,tested_people_log_group_number)) %>% filter(wikidata_id=="Q148") %>% 
        mutate(group=paste(dataset, wikidata_id,tested_people_log_group_number)) %>%
        arrange(date_asdate) #%>%

p1a <- test %>% 
ggplot() + 
   geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("China Q148 tested_people")

p1b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("China Q148 tested_people")+ ylab("Daily Percent Change tested_people")
   

#p1a / p1b

#India
#"Q668"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,tested_people_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q668") %>% 
        mutate(group=paste(dataset, wikidata_id,tested_people_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( tested_people_log_y_hat_percent_change = breakpoints(formula=tested_people_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p2a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("India Q668 tested_people")

p2b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("India Q668 tested_people")+ ylab("Daily Percent Change tested_people")
 
  
#p2a / p2b

#Bexar
#"Q16861"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,tested_people_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q16861") %>% 
        mutate(group=paste(dataset, wikidata_id,tested_people_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( tested_people_log_y_hat_percent_change = breakpoints(formula=tested_people_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p3a <- test %>%
      ggplot() + 
         geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
         geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
         ggtitle("Bexar County Q16861 tested_people")

p3b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Bexar County Q16861 tested_people") + ylim(0,100)+ ylab("Daily Percent Change tested_people")
   
#p3a / p3b



#Italy
#"Q38"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,tested_people_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q38") %>% 
        mutate(group=paste(dataset, wikidata_id,tested_people_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( tested_people_log_y_hat_percent_change = breakpoints(formula=tested_people_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p4a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("Italy Q38 tested_people")

p4b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("Italy Q38 tested_people")+ ylab("Daily Percent Change tested_people")
   
    
#p4a / p4b



#South Korea
#"Q884"

test <- lhs_long_clean_imputed %>% mutate(group=paste(dataset,wikidata_id,tested_people_log_y_hat_percent_change)) %>% filter(wikidata_id=="Q884") %>% 
        mutate(group=paste(dataset, wikidata_id,tested_people_log_group_number)) %>%
        arrange(date_asdate) #%>%
        #mutate( tested_people_log_y_hat_percent_change = breakpoints(formula=tested_people_log_y_hat_percent_change ~ 1, data=. ) %>% fitted.values() )


p5a <- test %>%
ggplot() + 
   geom_point( aes(x=date_asdate, y=tested_people_log, color=dataset), alpha=.3) +
   geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
   #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
   theme_bw() +
   ggtitle("South Korea Q884  tested_people")

p5b <- test %>%
       ggplot() + 
         geom_point( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change, color=dataset), alpha=.3) +
         geom_line(aes(x=date_asdate , y=tested_people_log_y_hat_percent_change_y_hat ), alpha=1, color="black") +
         #geom_smooth( aes(x=date_asdate , y=tested_people_log_y_hat_percent_change), alpha=.3, span=.05) + #, span=.05
         #geom_line( aes(x=date_asdate, y=tested_people_log_y_hat, color=dataset, group=group)) + #
         #geom_line(data=temp_df2, aes(x=date_asdate, y=y_hat_mean), color="black", linetype = "dashed") +
         theme_bw() +
   ggtitle("South Korea Q884 tested_people") + ylab("Daily Percent Change tested_people")
   
    
#p5a / p5b

Note that China counts of testing are almost never given at the national level. We have some broken down by specific provinces but tables usually don’t have a “China” row.

(p0a + p1a + p2a ) / (p0b + p1b + p2b )

(p3a + p4a + p5a) / (p3b + p4b + p5b)

Aligning Curves by Takeoff

library(infotheo)
#Once we removed the no variance places my alignment has more mutual information than either first confirmed or 100 confirmed
mutinformation(X=df_slopes %>% dplyr::select(t,t_alligned,t_alligned_firstconfirmed,confirmed_log_y_hat_percent_change_y_hat) %>% discretize(), method="emp") #we outperformed t_alligned_100confirmed but it wasn't avail for most

#df_slopes %>% filter(abs(t_alligned)<20,abs(t_alligned_100confirmed_100)<20) %>% janitor::tabyl(t_alligned, t_alligned_100confirmed_100)
#hist(df_slopes$t_alligned - df_slopes$t_alligned_100confirmed_100, breaks=50)

Plot of curves raw and then curves alligned by takeoff start

The idea here is that completely unconstrained, COVID-19 growth should follow a logistic curve, flat, upswing, constant growth, downswing, and flat again. The assumption of no unconstrained growth no longer holds because the world is reacting, but there’s still a pretty uniformly characteristic upswing across geographic units. We look for this signal of the largest first difference in the daily percent change, call that the takeoff date, and then allign all the time series with that date as 0.

p_t_alligned_firstconfirmed  / p_t_alligned 

Plots by Countries

We have to add geocodes to the map placements

admin0 <- readRDS("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_in/admin0.Rds")
admin1 <- readRDS("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_in/admin1.Rds")
admin2 <- readRDS("/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_in/admin2.Rds")

rex_clean <- function(x){ x %>% stringi::stri_trans_general("latin-ascii") %>% stringi::stri_replace_all(regex="[^A-Za-z0-9]","") %>% tolower() } #so individually, each string should be devoid of spaces,noncharacters, and nonlatin

rex_admin_function <- function(x) {
  x %>% 
  left_join(admin0 ) %>%
  left_join(admin1 )  %>%
  left_join(admin2 ) %>%
  mutate(gid=ifelse(!is.na(admin2_name_clean) & admin2_name_clean!='',gid2,ifelse(!is.na(admin1_name_clean) & admin1_name_clean!='', gid1, gid0))) %>%
  mutate(wikidata_id=ifelse(!is.na(admin2_name_clean) & admin2_name_clean!='',wikidata_id2,ifelse(!is.na(admin1_name_clean) & admin1_name_clean!='', wikidata_id1, wikidata_id0))) %>%
  mutate(geonameid=ifelse(!is.na(admin2_name_clean) & admin2_name_clean!='',geonameid2,ifelse(!is.na(admin1_name_clean) & admin1_name_clean!='', geonameid1, geonameid0))) %>%
  mutate(admin_level=ifelse(!is.na(admin2_name_clean) & admin2_name_clean!='',2,ifelse(!is.na(admin1_name_clean) & admin1_name_clean!='', 1, 0)))
}
install.packages("geofacet")
# or from github:
# devtools::install_github("hafen/geofacet")
library(geofacet)
head(us_state_grid2)
NA

Confirmed, Deaths, Tests

By country


head(world_countries_grid1)

temp1 <- df_slopes %>%
          filter(!gid %>% str_detect("_") ) %>%
          left_join(geonames_small  ) %>% mutate(name_text=name_text %>% as.factor()) %>%
          left_join(world_countries_grid1, by=c('gid'='code_alpha3'))
temp2 <- temp1 %>% arrange(date_asdate) %>% filter(!duplicated(gid_geonameid_wikidata_id)) %>% mutate(name_text=name_text %>% as.factor())

p_confirmed_deaths_test_by_country <- temp1 %>% 
                                      ggplot() + 
                                         geom_line( aes(x=t_alligned, y=confirmed_log_y_hat), color="red") + # #t aligned is broken for the U.S. and some countries, all infinites
                                         geom_line( aes(x=t_alligned, y=deaths_log_y_hat), color="black") + #
                                         geom_line( aes(x=t_alligned, y=tested_people_log_y_hat), color="blue") + #
                                         theme_bw() +
                                         ggtitle("United States Covid-19: Log Tested (blue) Confirmed (red), Death (black)") +
                                        guides( color = FALSE) +
                                        facet_wrap(~name_text   ) +
                                        theme(
                                          strip.background = element_blank()
                                        ,  strip.text.x = element_blank()
                                        ) +
                                        geom_text(data=temp2,x=0,y=14,aes(label=name_text), size=3) +
                                        ylab("Counts (log)") +
                                        xlab("Days before/Since Takeoff in Confirmed Numbers") +
                                        facet_geo(~code_alpha3) 

U.S. by State

India by State

p_confirmed_deaths_test_by_state_india

Tomorrow morning I think my job is to first difference all of these. How many tests, how many confirmed, how many dead each day. Find the lags and leads with the highest correlation between those three, possibly varying by country.

What this gives us is a nice normalized dataset where the task is to predict the shape of that distribution. We could try to predict time until the takeoff, the intensity of the growth at the takeoff point, the time until it returns to zero, the area under the curve, or every nook and change.

How does testing vary over this?

Plot some specific countries

lm1 <- lm(deaths ~  confirmed,data=lhs_long_median %>% filter(CFR<1))
lm2 <- lm(deaths ~ tested_people + confirmed,data=lhs_long_median %>% filter(CFR<1))

library(ggRandomForests); #install.packages('ggRandomForests')
rf1 <- rfsrc(deaths~ confirmed,
                      data=lhs_long_median %>% filter(CFR<1) %>% as.data.frame() )
gg_e <- gg_error(rf1)
gg_v <- gg_variable(rf1)
plot(gg_v, panel=TRUE, se=.95, span=1.2, alpha=.4) 

rf1 <- rfsrc(deaths~ confirmed + tested_people,
                      data=lhs_long_median %>% filter(CFR<1) %>% as.data.frame() )
gg_e <- gg_error(rf1)
gg_v <- gg_variable(rf1)
plot(gg_v, panel=TRUE, se=.95, span=1.2, alpha=.4)


rf2 <- rfsrc(CFR ~  tested_people_log,
                      data=lhs_long_median %>% 
                      mutate(CFR=deaths/confirmed) %>%
                      mutate(tested_people_log=log(tested_people+1)) %>%
                      filter(CFR<1) %>% as.data.frame()
             )
gg_v <- gg_variable(rf2)
plot(gg_v, panel=TRUE, se=.95, span=1.2, alpha=.4)

rf2 <- rfsrc(CFR ~  tested_people_log + confirmed_log,
                      data=lhs_long_median %>% 
                      mutate(CFR=deaths/confirmed) %>%
                      mutate(tested_people_log=log(tested_people+1)) %>%
                      mutate(confirmed_log=log(confirmed+1)) %>%
                      filter(CFR<1) %>% as.data.frame()
             )
gg_v <- gg_variable(rf2)
plot(gg_v, panel=TRUE, se=.95, span=1.2, alpha=.4)


#Throw in time
rf3 <- rfsrc(CFR ~  positive_perc + tested_people_log,
                                    data=lhs_long_median %>% 
                                    mutate(CFR=deaths/confirmed) %>%
                                    mutate(positive_perc=confirmed/tested_people) %>%
                                    mutate(tested_people_log=log(tested_people+1)) %>%
                                    mutate(confirmed_log=log(confirmed+1)) %>%
                                    filter(CFR<1) %>% as.data.frame()
             )
gg_v <- gg_variable(rf3)
plot(gg_v, panel=TRUE, se=.95, span=1.2, alpha=.4)

partial_Boston <- plot.variable(rf3,
partial=TRUE, sorted=FALSE,
show.plots = FALSE )

gg_p <- gg_partial(partial_Boston)
plot(gg_p, panel=TRUE, points = F )


copper_cts <-quantile_pts(lhs_long_median$tested_people_log, groups = 6, intervals = TRUE)
partial_coplot_Boston <- gg_partial_coplot(rf2, xvar="confirmed_log",
                                         groups=rm_grp,
                                         show.plots=FALSE)



summary(lhs_long_median$CFR)

lhs_long_median %>% filter(confirmed>10) %>% filter(CFR<1) %>% pull(CFR) %>% summary() #0.0297297  that's a median CFR of about 3%
lhs_long_median %>% filter(confirmed>10) %>% filter(CFR<1) %>% pull(CFR) %>% hist(breaks=50)

lhs_long_median %>% filter(confirmed>10) %>% filter(CFR<1) %>% ggplot(aes(x=CFR)) + geom_density()
#This code is now depricated in favor of the tree base method above

places <- lhs_long_clean$wikidata_id %>% unique() %>% na.omit() ; length(places)
datasets <- lhs_long_clean$dataset %>% unique() %>% na.omit() ; table(dataset)

temp_list <- list()
for(p in places){
    print(p)
    for(d in datasets){
      temp <- NULL
      temp <- lhs_long_clean %>% 
              arrange(date_asdate) %>% 
              filter(dataset %in% d) %>% 
              filter(wikidata_id %in% p) %>% 
              mutate(confirmed_log=log(confirmed+1)) %>%
              mutate(deaths_log=log(deaths+1)) %>%
              mutate(tested_people_log=log(tested_people+1)) %>%
              mutate(t= as.numeric(date_asdate) - min(as.numeric(date_asdate)) +1  ) %>% #start at 1 to make indexing easier
              mutate(i= row_number()  ) # actually need this
        
      i_original <- temp$i
      
      if( nrow(temp)==0 ) { next} #print("error");
      print(p)
      
      #bp <- breakpoints(confirmed_log ~ 1, data=temp)
      bp <- NULL
      lm1 <- NULL
      y_hat <- NA
      cdf <- NULL
      try({
            #if it fails fall back to just a lm
        lm1 <- lm(confirmed_log ~ 1 + t, data=temp)
    
        cdf <- data.frame(
                          t= 1, 
                          confirmed_log_intercept= coef(lm1)[1],
                          confirmed_log_slope= coef(lm1)[2],
                          confirmed_log_slope_break=0
                          )
        confirmed_log_y_hat=fitted.values(lm1)
      })
      
      try({
        bp <- breakpoints(confirmed_log ~ 1 + t, data=temp, h=3)
        
        cdf <- data.frame(
                          i= c(1,bp$breakpoints), 
                          confirmed_log_intercept= coef(bp)[,1],
                          confirmed_log_slope= coef(bp)[,2],
                          confirmed_log_slope_break=1
                          )
        confirmed_log_y_hat=fitted.values(bp)
      })
      
      try({
        temp2 <- temp
        temp2$confirmed_log_y_hat <- NA
        temp2$confirmed_log_y_hat <- confirmed_log_y_hat
        
        temp2 <- temp2 %>% 
                left_join(cdf) 
        q=paste0(p,"_",d)
        temp2 <- temp2 %>% 
                  expand(dataset, gid,geonameid, wikidata_id,t=min(temp$t):max(temp$t)) %>% #expand this to include all the t 
                  left_join(temp2) %>% 
                  mutate(date_asdate=min(date_asdate, na.rm=T)-1+t) %>% #go back interp date again
                  mutate(confirmed_log_slope_break = confirmed_log_slope_break %>% replace_na(0) %>% cumsum() ) %>%
                  fill(confirmed_log_intercept) %>%
                  fill(confirmed_log_slope) %>%
                  mutate(confirmed_log_y_hat= confirmed_log_intercept + confirmed_log_slope*t ) %>% 
                  mutate(confirmed_log_slope_percent_change = round((exp(confirmed_log_slope)-1)*100,2)) 

        temp_list[[as.character(q)]] <- temp2
      })
      #if( is.na( temp_list[[as.character(q)]]$y_hat) ) {print("error"); break}
    }
}
#"13055"
temp_df <- bind_rows(temp_list)
dim(temp_df) #bigger because we're interpolating now

# install.packages("devtools")
#devtools::install_github("tidyverse/multidplyr")

library(multidplyr)
library(dplyr, warn.conflicts = FALSE)
#cluster <- new_cluster(4)

#need to supress messages
rex_function <- function(x){
  temp=data.frame(confirmed_log_slope=x)
  tryCatch({
    #if there's an NA in x we get an error because breakpoints is one short
    prediction <- breakpoints(formula=confirmed_log_slope ~ 1, data=temp, h=3) %>% fitted.values()
    result=rep(NA, length(x) )
    result[!is.na(x)] <-prediction
    return(result)
    
  }, error=function(e){})
  
  return( rep(NA, length(x) ) )
         
}
#didn't take too long now

#library(multidplyr)
#library(dplyr, warn.conflicts = FALSE)
#cluster <- new_cluster(4)

library(tictoc)
tic()
library(strucchange)
test <- temp_df %>% head(20000)
test3 <- test %>% 
                group_by(wikidata_id) %>% 
                #partition(cluster) %>%
                arrange(date_asdate) %>%
                #mutate( confirmed_log_slope_y_hat = breakpoints(formula=confirmed_log_slope ~ 1, data=. ) %>% fitted.values() ) %>% 
                mutate( confirmed_log_slope_y_hat = rex_function(confirmed_log_slope) ) %>%  #fails on the cluster
                ungroup() #%>%
                #collect()
toc() #48 seconds for 10k #122 seconds for 20k

saveRDS(temp_df, "/media/skynet2/905884f0-7546-4273-9061-12a790830beb/rwd_github_private/NESScovid19/data_temp/lhs_long_interpolated.Rds")
LS0tCnRpdGxlOiAiVGhlIE1hY2hpbmUgTGVhcm5pbmcgZm9yIFNvY2lhbCBTY2llbmNlIEdsb2JhbCBTdWJuYXRpb25hbCBDb3ZpZCBDb3VudHMgRGF0c2V0IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQpkYXRlOiAKYXV0aG9yOiAKYWZmaWxpYXRpb246IERpcmVjdG9yLCBNYWNoaW5lIExlYXJuaW5nIGZvciBTb2NpYWwgU2NpZW5jZSBMYWIsIENlbnRlciBmb3IgUGVhY2UgYW5kIFNlY3VyaXR5IFN0dWRpZXMsIFVuaXZlcnNpdHkgb2YgQ2FsaWZvcm5pYSBTYW4gRGllZ28KZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpSZXggVy4gRG91Z2xhc3MKCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJsb2NrcXVvdGUgewogICAgcGFkZGluZzogMTBweCAyMHB4OwogICAgbWFyZ2luOiAwIDAgMjBweDsKICAgIGZvbnQtc2l6ZTogMTRweDsKICAgIGJvcmRlci1sZWZ0OiA1cHggc29saWQgI2VlZTsKfQo8L3N0eWxlPgoKIyBJbnRyb2R1Y3Rpb24KCiMjIExpYnJhcnkgTG9hZHMKCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CiNsaWJyYXJpZXMKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkodGlkeXZlcnNlKQoKI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigicm9wZW5zY2kvVVNBYm91bmRhcmllcyIpCiNkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInJvcGVuc2NpL1VTQWJvdW5kYXJpZXNEYXRhIikKbGlicmFyeShVU0Fib3VuZGFyaWVzKSA7ICNpbnN0YWxsLnBhY2thZ2VzKCdVU0Fib3VuZGFyaWVzJykKZGF0YShzdGF0ZV9jb2RlcykKCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShnZ2hpZ2hsaWdodCkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoUjApICAjIGNvbnNpZGVyIG1vdmluZyBhbGwgbGlicmFyeSBjb21tYW5kcyB0byB0b3AgLS0gdGhpcyBvbmUgd2FzIGluIGEgbG9vcCBiZWxvdwoKbGlicmFyeShXaWtpZGF0YVIpCmxpYnJhcnkoY291bnRyeWNvZGUpCgpsaWJyYXJ5KHVzbWFwKSA7ICMgaW5zdGFsbC5wYWNrYWdlcygndXNtYXAnKQpkYXRhKHN0YXRlcG9wKQojZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJyb3BlbnNjaS9VU0Fib3VuZGFyaWVzIikKI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigicm9wZW5zY2kvVVNBYm91bmRhcmllc0RhdGEiKQpsaWJyYXJ5KFVTQWJvdW5kYXJpZXMpIDsgI2luc3RhbGwucGFja2FnZXMoJ1VTQWJvdW5kYXJpZXMnKQpkYXRhKHN0YXRlX2NvZGVzKQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoc2YpCgpsaWJyYXJ5KGpzb25saXRlKQoKI1RoaXMgaXMgdG9vIHNsb3cgaXQncyBkb3dubG9hZGluZyBlYWNoCmxpYnJhcnkoR0FETVRvb2xzKQpsaWJyYXJ5KHN0cnVjY2hhbmdlKSA7ICNpbnN0YWxsLnBhY2thZ2VzKCdzdHJ1Y2NoYW5nZScpCmxpYnJhcnkodHNpYmJsZSkKCmxpYnJhcnkocGF0Y2h3b3JrKQoKYGBgCiMjIERhdGEgTG9hZGluZyBhbmQgQ2xlYW5pbmcKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OCx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQoKbGlicmFyeSh0c2liYmxlKQoKbGhzX2xvbmcgPC0gcmVhZFJEUygiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvbGhzX2xvbmcuUmRzIikKI2RpbShsaHNfbG9uZykgIzE4NywzMDUKCmxoc19sb25nX2NsZWFuIDwtIGxoc19sb25nICU+JSAKICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChkYXRhc2V0LCBnaWQsZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCAsZGF0ZV9hc2RhdGUsIGNvbmZpcm1lZCwgZGVhdGhzLCB0ZXN0ZWRfcGVvcGxlLCB0ZXN0ZWRfc2FtcGxlcykgJT4lCiAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGRhdGFzZXQsIGdpZCxnZW9uYW1laWQsIHdpa2lkYXRhX2lkICxkYXRlX2FzZGF0ZSkgJT4lICNpZiB0aGUgc2FtZSBzb3VyY2UgaGFzIG11bHRpcGxlIHZhbHVlcyBvbiB0aGUgc2FtZSB0aGluZyBvbiB0aGUgc2FtZSBkYXksIG9yIGRpZmZlcmVudCB2YWx1ZXMgYWNyb3NzIHVubWVyZ2VkIG9icywgdGhlbiB0YWtlIHRoZSBtYXgKICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlX2FsbChtYXgsIG5hLnJtPVQpICU+JSAKICAgICAgICAgICAgICAgICAgdW5ncm91cCgpICU+JQogICAgICAgICAgICAgICAgICBtdXRhdGVfaWYoaXMubnVtZXJpYywgbGlzdCh+bmFfaWYoLiwgLUluZikpKSAlPiUKICAgICAgICAgICAgICAgICAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGxpc3Qofm5hX2lmKC4sIEluZikpKSAlPiUKICAgICAgICAgICAgICAgICAgbXV0YXRlKGRhdGFzZXRfZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZD0gcGFzdGUoZGF0YXNldCxnaWQsZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgc2VwPSJfIikgICkgJT4lCiAgICAgICAgICAgICAgICAgIG11dGF0ZShnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkPSBwYXN0ZShnaWQsZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgc2VwPSJfIikgICkgJT4lCiAgCiAgICAgICAgICAgICAgICAgIGZpbHRlcighaXMubmEoZGF0ZV9hc2RhdGUpKSAlPiUKICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICNGaXJzdCBkcm9wIGFueXRoaW5nIHRoYXQncyBuZWdhdGl2ZS4gU2hvdWxkbid0IGJlIGFueSBuZWdhdGl2ZXMuCiAgICAgICAgICAgICAgICAgIGZpbHRlcihpcy5uYShjb25maXJtZWQpIHwgY29uZmlybWVkPj0wKSAlPiUKICAgICAgICAgICAgICAgICAgZmlsdGVyKGlzLm5hKGRlYXRocykgfCBkZWF0aHM+PTApICU+JQogICAgICAgICAgICAgICAgICBmaWx0ZXIoaXMubmEodGVzdGVkX3Blb3BsZSkgfCB0ZXN0ZWRfcGVvcGxlPj0wKSAlPiUKICAgICAgICAgICAgICAgICAgZmlsdGVyKGlzLm5hKHRlc3RlZF9zYW1wbGVzKSB8IHRlc3RlZF9zYW1wbGVzPj0wKSAlPiUKICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICNUaGVuIHNldCAwcyB0byBOQSwgd2UgZG9uJ3QgdHJ1c3QgTkFzCiAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWQ9aWZlbHNlKGNvbmZpcm1lZD09MCwgTkEsIGNvbmZpcm1lZCkpICU+JQogICAgICAgICAgICAgICAgICBtdXRhdGUoZGVhdGhzPWlmZWxzZShkZWF0aHM9PTAsIE5BLCBkZWF0aHMpKSAlPiUKICAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGU9aWZlbHNlKHRlc3RlZF9wZW9wbGU9PTAsIE5BLCB0ZXN0ZWRfcGVvcGxlKSkgJT4lCiAgICAgICAgICAgICAgICAgIG11dGF0ZSh0ZXN0ZWRfc2FtcGxlcz1pZmVsc2UodGVzdGVkX3NhbXBsZXM9PTAsIE5BLCB0ZXN0ZWRfc2FtcGxlcykpICU+JQogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICNUaGVuIGNoZWNrIGZpcnN0IGRpZmZlcmVuY2VzIGFuZCBkcm9wIGFueXRoaW5nIHRoYXQgZG9lc24ndCB3ZWFrbHkgaW5jcmVhc2UgbW9ub3RvbmljYWxseQogICAgICAgICAgICAgICAgICBncm91cF9ieShkYXRhc2V0LCBnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9jdW1tYXg9Y29uZmlybWVkICU+JSByZXBsYWNlX25hKDApICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdW1tYXgoKSwgZGVhdGhzX2N1bW1heD1kZWF0aHMlPiUgcmVwbGFjZV9uYSgwKSAlPiUgY3VtbWF4KCksIHRlc3RlZF9wZW9wbGVfY3VtbWF4PXRlc3RlZF9wZW9wbGUlPiUgcmVwbGFjZV9uYSgwKSAlPiUgY3VtbWF4KCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3RlZF9zYW1wbGVzX2N1bW1heD10ZXN0ZWRfc2FtcGxlcyU+JSByZXBsYWNlX25hKDApICU+JSBjdW1tYXgoKSkgJT4lCiAgICAgICAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUgIAogIAogICAgICAgICAgICAgICAgICAjQWJvdXQgNGsgb2YgdGhlc2Ugb2JzZXJ2YXRpb25zIHNob3cgYSBkZWNyZWFzZSBmcm9tIG9uZSB0aW1lIHN0ZXAgdG8gdGhlIG5leHQgd2hpY2ggc3VnZ2VzdHMgZWl0aGVyIGFuIG9yaWdpbmFsIGVycm9yIG9yIGEgam9pbmluZyBlcnJvcgogICAgICAgICAgICAgICAgICAjV2UncmUgZ29pbmcgdG8gc3RyYWlnaHQgZHJvcCB0aG9zZSBvYnNlcnZhdGlvbnMgYXMgYSBjbGVhbmluZyBzdGVwCiAgICAgICAgICAgICAgICAgICN0aGlzIGlzbid0IGVub3VnaCBiZWNhdXNlIGlmIHlvdSBoYXZlIGNvbnNlY3V0aXZlIG1pc3Rha2VzIGl0J2xsIHNob3cgYSBwb3NpdGl2ZSBmZCBldmVuIGlmIGl0J3Mgbm90IGdvb2QgZW5vdWdoCiAgICAgICAgICAgICAgICAgIGZpbHRlciggKGlzLm5hKGNvbmZpcm1lZCkgfCBjb25maXJtZWQ+PWNvbmZpcm1lZF9jdW1tYXgpICYgICNuZXZlciBhbGxvdyBmb3IgYSByZXZlcnNhbAogICAgICAgICAgICAgICAgICAgICAgICAgIChpcy5uYShkZWF0aHMpIHwgZGVhdGhzPj1kZWF0aHNfY3VtbWF4KSAmICAgICAgICAjbmV2ZXIgYWxsb3cgZm9yIGEgcmV2ZXJzYWwKICAgICAgICAgICAgICAgICAgICAgICAgICAoaXMubmEodGVzdGVkX3Blb3BsZSkgfCB0ZXN0ZWRfcGVvcGxlPj10ZXN0ZWRfcGVvcGxlX2N1bW1heCkgJiAgI25ldmVyIGFsbG93IGZvciBhIHJldmVyc2FsCiAgICAgICAgICAgICAgICAgICAgICAgICAgKGlzLm5hKHRlc3RlZF9zYW1wbGVzKSB8IHRlc3RlZF9zYW1wbGVzPj10ZXN0ZWRfc2FtcGxlc19jdW1tYXgpICAjbmV2ZXIgYWxsb3cgZm9yIGEgcmV2ZXJzYWwKICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JQogICN3ZSdyZSBnb2luZyB0byBnbyBvbmUgc3RlcCBmdXJ0aGVyIGFuZCByZXF1aXJlIGVpdGhlciBjb25maXJtZWQgb3IgdGVzdGVkIHRvIGJlIHN0cmljdGx5IGhpZ2hlcgogICNJbiB3b3JkcywgZHVyaW5nIGFuIGVwaXNvZGUgd2UgZG9uJ3QgYmVsaWV2ZSByZXBvcnRzIG1lYW4gIm5vIG5ldyBjYXNlcyIganVzdCBubyBuZXcgZ29vZCByZXBvcnRpbmcKICAjbWV0YWJpb3RhIGlzIHRoZSB3b3JzdCBvZmZlbmRlciBoZXJlIHNvIHJlc3RyaWN0aW5nIGl0IHRvIGp1c3QgdGhhdAogIGZpbHRlciggISgKICAgICAgICAgICAgZGF0YXNldD09Im1ldGFiaW90YSIgJiAjaXMgbWV0YWJpb3RhCiAgICAgICAgICAgICghaXMubmEoY29uZmlybWVkKSAmICAgI3dpdGggYSBub24gbWlzc2luZyBjb25maXJtZWQKICAgICAgICAgICAgICBjb25maXJtZWQ8PWNvbmZpcm1lZF9jdW1tYXggKSAjdGhhdCBpcyBlcXVhbCB0byBvciBsZXNzIHRoYW4gdGhlIGN1bXVsYXRpdmUgbWF4IHVudGlsIHRoZW4uCiAgICAgICAgICAgICkgI3JlamVjdCB0aGVzZQogICAgICAgICAgKSAlPiUgI21ldGFiaW90YSBpcyByZWFsbHkgcHJvYmxlbWF0aWMgOTAlIG9mIHdoYXQgd2UncmUgZG9pbmcgaXMgdHJ5aW5nIHRvIGFjY291bnQgZm9yIGl0CiAgCiAgI0Fsc28gcmVqZWN0IGFueSB3aGVyZSBkZWF0aHMgYXJlIGdyZWF0ZXIgdGhhbiBjb25maXJtZWQKICBmaWx0ZXIoaXMubmEoY29uZmlybWVkKSB8IGlzLm5hKGRlYXRocykgfCBjb25maXJtZWQ+PWRlYXRocykgJT4lCiAgCiAgI2Fsc28gcmVqZWN0IGFueSB3aGVyZSBjb25maXJtZWQgZG9lc24ndCB2YXJ5IAogIGdyb3VwX2J5KGdpZCAsICBnZW9uYW1laWQgLHdpa2lkYXRhX2lkKSAlPiUgI2Nob3NlIG5vdCB0byBkbyBieSBkYXRhc2V0IGJlY2F1c2UgdGVzdGluZyBkYXRhc2V0cyBtaWdodCBub3QgaGF2ZSBjb25maXJtZWQKICAgIGZpbHRlcih2YXIoY29uZmlybWVkLCBuYS5ybT1UKT4wKSAlPiUKICB1bmdyb3VwKCkKCiAgCiNkaW0obGhzX2xvbmdfY2xlYW4pICMyODEsNDY0ICMyOTIsNTgwICMyOTkyMTMgIzE4MSw1NjMKCnNhdmVSRFMobGhzX2xvbmdfY2xlYW4sCiAgICAgICAgIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2xoc19sb25nX2NsZWFuZC5SZHMiKQoKYGBgCgpTdW1tYXJ5IFN0YXRpc3RpY3Mgb2YgT3VyIERhdGEKCmBgYHtyfQpwcmludCgiTnVtYmVyIG9mIG9ic2VydmF0aW9ucyIpCmRpbShsaHNfbG9uZ19jbGVhbikKCnByaW50KCJOdW1iZXIgb2YgbG9jYXRpb25zIikKbGhzX2xvbmdfY2xlYW4kd2lraWRhdGFfaWQgJT4lIHVuaXF1ZSgpICU+JSBsZW5ndGgoKSAjMywzNzMKCnByaW50KCJOdW1iZXIgb2YgRGF5cyIpCmxoc19sb25nX2NsZWFuJGRhdGVfYXNkYXRlICU+JSB1bmlxdWUoKSAlPiUgbGVuZ3RoKCkgIzExMwoKbGlicmFyeShEVCkgI2h0dHBzOi8vcnN0dWRpby5naXRodWIuaW8vRFQvCmxoc19sb25nX2NsZWFuICU+JSBjb3VudChkYXRhc2V0KSAlPiUgYXJyYW5nZSgtbikgJT4lIERUOjpkYXRhdGFibGUob3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDIwLCBhdXRvV2lkdGggPSBUUlVFKSkKCiNsaWJyYXJ5KGd0KQojbGhzX2xvbmdfY2xlYW4gJT4lIGNvdW50KGRhdGFzZXQpICU+JSBhcnJhbmdlKC1uKSAlPiUgZ3QoKSAlPiUgCiMgdGFiX2hlYWRlcigKIyAgICB0aXRsZSA9IG1kKCJMb2NhdGlvbi1EYXlzIGJ5IERhdGFzZXQiKSMsCiMgICAgI3N1YnRpdGxlID0gIk51bWJlciBvZiBEYXlzIHdpdGggRGF0YSBieSBEYXRhc2V0IgojICApICU+JQojICBmbXRfbWlzc2luZyggY29sdW1ucz1ldmVyeXRoaW5nKCksIHJvd3M9TlVMTCxtaXNzaW5nX3RleHQgPSAwKQoKYGBgCgoKIyBTcGF0aWFsIFZhcmlhdGlvbiBpbiBEYXRhIEF2YWlsYWJpbGl0eQoKIyMgQ291bnRyeSBMZXZlbCBEYXRhIEF2YWlsYWJpbGl0eQoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQoKI2dhZG0zNiA9IHN0X3JlYWQoIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2dhZG0vZGF0YV9pbi9nYWRtMzZfZ3BrZy9nYWRtMzYuZ3BrZyIpCiNzdF9sYXllcnMoIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2dhZG0zNl9ieWNvdW50cnkvZ2FkbTM2X2xldmVsc19ncGtnL2dhZG0zNl9sZXZlbHMuZ3BrZyIpCmdhZG0zNl9sZXZlbHNfMCA9IHN0X3JlYWQoIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2dhZG0zNl9ieWNvdW50cnkvZ2FkbTM2X2xldmVsc19ncGtnL2dhZG0zNl9sZXZlbHMuZ3BrZyIsIGxheWVyPSJsZXZlbDAiKSAgJT4lCiAgICAgICAgICAgICAgICAgIHN0X3NpbXBsaWZ5KHByZXNlcnZlVG9wb2xvZ3kgPSBGQUxTRSwgZFRvbGVyYW5jZSA9MC4xKSAjICAwLjAyNSB0aGlzIGlzIHN1cHBvc2VkbHkgYnJva2VuIHVwIGJ5IDYgbGV2ZWxzIGFuZCBzbyBzaG91bGQgaGF2ZSB1LnMuIAoKI3Bsb3QoZ2FkbTM2X2xldmVsc18wKQojZGltKGdhZG0zNl9sZXZlbHNfMF9zZiRzZikKI2dhZG1fcGxvdChnYWRtMzZfbGV2ZWxzXzBfc2YpCmxoc19sb25nX3BsYWNlX3NvdXJjZXMgPC0gbGhzX2xvbmcgICU+JSBkcGx5cjo6c2VsZWN0KGdpZCwgICBnZW9uYW1laWQsIHdpa2lkYXRhX2lkLCBkYXRhc2V0KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGdpZCwgIGdlb25hbWVpZCwgd2lraWRhdGFfaWQpICU+JSBjb3VudChkYXRhc2V0KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoZ2lkLCAgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShkYXRhc2V0c19uPW4oKSkgCgpwMCA8LSBnYWRtMzZfbGV2ZWxzXzAgJT4lIAogICAgICBsZWZ0X2pvaW4obGhzX2xvbmdfcGxhY2Vfc291cmNlcyAlPiUgZHBseXI6OnNlbGVjdChnaWQ9Z2lkLCBkYXRhc2V0c19uKSAlPiUgIGxlZnRfam9pbiggZ2FkbTM2X2xldmVsc18wICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGRwbHlyOjpzZWxlY3QoZ2lkPUdJRF8wLCBOQU1FXzApICAlPiUgZGlzdGluY3QoKSAgKQogICAgICAgICAgICAgICAgKSAlPiUKICAgICAgI3JlcGxhY2VfbmEobGlzdChkYXRhc2V0c19uID0gMCkpICU+JSAKICAgICAgZ2dwbG90KCkgKyBnZW9tX3NmKGFlcyhmaWxsID0gZGF0YXNldHNfbikpICsKICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9InJlZCIsIGhpZ2g9ImdyZWVuIikgKwogICAgICB0aGVtZV9idygpIApgYGAKCgoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KcDAgKyBnZ3RpdGxlKCJDb3ZpZCBDb3VudCBEYXRhIEF2YWlsYWJpbGl0eSBhdCB0aGUgQ291bnRyeSBMZXZlbCIpCmBgYAoKYGBge3J9CnRlbXAgPC0gZ2FkbTM2X2xldmVsc18wICU+JQogICBsZWZ0X2pvaW4oCiAgIGxoc19sb25nICAlPiUgY291bnQoZ2lkLCBkYXRhc2V0KSAlPiUgcmVuYW1lKEdJRF8wPWdpZCkgI3RoZXJlIGFyZSBzdGlsbCBkdXBlIGdlb25hbWVzIHdpa2lkYXRhIHRvIGdpZCBtYXRjaGVzIHRoYXQgbmVlZCB0byBiZSBmaXhlZCBnZW9uYW1laWQsIHdpa2lkYXRhX2lkLCAKKSAKCnRlbXBfd2lkZSA8LSB0ZW1wICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGRwbHlyOjpzZWxlY3QoQ291bnRyeT1OQU1FXzAsIGRhdGFzZXQsIG4pICU+JSBkaXN0aW5jdCgpICU+JSBwaXZvdF93aWRlciggaWRfY29scyA9IENvdW50cnksIG5hbWVzX2Zyb20gPSBkYXRhc2V0LAogIHZhbHVlc19mcm9tID0gbiwgdmFsdWVzX2ZpbGwgPSBOVUxMLCB2YWx1ZXNfZm4gPSBOVUxMKSAKCnRlbXBfd2lkZSAlPiUgRFQ6OmRhdGF0YWJsZShvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMjAsIGF1dG9XaWR0aCA9IFRSVUUpKQoKI2luc3RhbGwucGFja2FnZXMoJ2d0JykKI2xpYnJhcnkoZ3QpCiN0ZW1wX3dpZGUgJT4lIGd0KCkgJT4lIAojIHRhYl9oZWFkZXIoCiMgICAgdGl0bGUgPSBtZCgiRGF0YSBBdmFpbGFiaWxpdHkgYnkgQ291bnRyeSIpLAojICAgIHN1YnRpdGxlID0gIk51bWJlciBvZiBEYXlzIHdpdGggRGF0YSBieSBEYXRhc2V0IgojICApICU+JQojICBmbXRfbWlzc2luZyggY29sdW1ucz1ldmVyeXRoaW5nKCksIHJvd3M9TlVMTCxtaXNzaW5nX3RleHQgPSAwKQoKYGBgCgojIyBTdGF0ZS9Qcm92aW5jZSBMZXZlbCBEYXRhIEF2YWlsYWJpbGl0eQoKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KZ2FkbTM2X2xldmVsc18xID0gc3RfcmVhZCgiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvZ2FkbTM2X2J5Y291bnRyeS9nYWRtMzZfbGV2ZWxzX2dwa2cvZ2FkbTM2X2xldmVscy5ncGtnIiwgbGF5ZXI9ImxldmVsMSIpICAlPiUKICBzdF9zaW1wbGlmeShwcmVzZXJ2ZVRvcG9sb2d5ID0gRkFMU0UsIGRUb2xlcmFuY2UgPTAuMSkgIyAgMC4wMjUgdGhpcyBpcyBzdXBwb3NlZGx5IGJyb2tlbiB1cCBieSA2IGxldmVscyBhbmQgc28gc2hvdWxkIGhhdmUgdS5zLiAKCgpwMSA8LSBnYWRtMzZfbGV2ZWxzXzEgJT4lIAogIGxlZnRfam9pbihsaHNfbG9uZ19wbGFjZV9zb3VyY2VzICU+JSBkcGx5cjo6c2VsZWN0KGdpZD1naWQsIGRhdGFzZXRzX24pICU+JSAgbGVmdF9qb2luKCBnYWRtMzZfbGV2ZWxzXzEgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OnNlbGVjdChnaWQ9R0lEXzEsIE5BTUVfMSkgJT4lIGRpc3RpbmN0KCkgICkKICApICU+JQogICNyZXBsYWNlX25hKGxpc3QoZGF0YXNldHNfbiA9IDApKSAlPiUgCiAgZ2dwbG90KCkgKyBnZW9tX3NmKGFlcyhmaWxsID0gZGF0YXNldHNfbikpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0icmVkIiwgaGlnaD0iZ3JlZW4iKSArCiAgdGhlbWVfYncoKSAKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQpwMQpgYGAKCmBgYHtyfQp0ZW1wIDwtIGdhZG0zNl9sZXZlbHNfMSAlPiUKICAgbGVmdF9qb2luKAogICBsaHNfbG9uZyAgJT4lIGNvdW50KGdpZCwgZGF0YXNldCkgJT4lIHJlbmFtZShHSURfMT1naWQpICN0aGVyZSBhcmUgc3RpbGwgZHVwZSBnZW9uYW1lcyB3aWtpZGF0YSB0byBnaWQgbWF0Y2hlcyB0aGF0IG5lZWQgdG8gYmUgZml4ZWQgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgCikgCgp0ZW1wX3dpZGUgPC0gdGVtcCAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBkcGx5cjo6c2VsZWN0KENvdW50cnk9TkFNRV8wLCBBZG1pbjE9TkFNRV8xLCBkYXRhc2V0LCBuKSAlPiUgZGlzdGluY3QoKSAlPiUgcGl2b3Rfd2lkZXIoIGlkX2NvbHMgPSBDb3VudHJ5OkFkbWluMSwgbmFtZXNfZnJvbSA9IGRhdGFzZXQsCiAgdmFsdWVzX2Zyb20gPSBuLCB2YWx1ZXNfZmlsbCA9IE5VTEwsIHZhbHVlc19mbiA9IE5VTEwpICU+JSBtdXRhdGUodG90YWwgPSByb3dTdW1zKC5bLWMoMSwyKV0sIG5hLnJtID0gVCkpCgp0ZW1wX3dpZGUgJT4lIGZpbHRlcih0b3RhbD4wKSAlPiUgRFQ6OmRhdGF0YWJsZShvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTAsIGF1dG9XaWR0aCA9IFRSVUUpKQoKYGBgCgojIyBDb3VudHkgRGlzdHJpY3QgTGV2ZWwgRGF0YSBBdmFpbGFiaWxpdHkKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KZ2FkbTM2X2xldmVsc18yID0gc3RfcmVhZCgiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvZ2FkbTM2X2J5Y291bnRyeS9nYWRtMzZfbGV2ZWxzX2dwa2cvZ2FkbTM2X2xldmVscy5ncGtnIiwgbGF5ZXI9ImxldmVsMiIpICAlPiUKICBzdF9zaW1wbGlmeShwcmVzZXJ2ZVRvcG9sb2d5ID0gRkFMU0UsIGRUb2xlcmFuY2UgPSAwLjAwMSkgIyAgMC4wMjUgdGhpcyBpcyBzdXBwb3NlZGx5IGJyb2tlbiB1cCBieSA2IGxldmVscyBhbmQgc28gc2hvdWxkIGhhdmUgdS5zLiBJIGhhdmUgdG8ga2VlcCBzaHJpbmtpbmcgaXQgc28gbWlzaXNuZyBnb2VzIHRvIHplcm8gCgpwMiA8LSBnYWRtMzZfbGV2ZWxzXzIgJT4lIAogIGxlZnRfam9pbihsaHNfbG9uZ19wbGFjZV9zb3VyY2VzICU+JSBkcGx5cjo6c2VsZWN0KGdpZD1naWQsIGRhdGFzZXRzX24pICU+JSAgbGVmdF9qb2luKCBnYWRtMzZfbGV2ZWxzXzIgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OnNlbGVjdChnaWQ9R0lEXzIsIE5BTUVfMikgJT4lIGRpc3RpbmN0KCkgICkKICApICU+JQogICNyZXBsYWNlX25hKGxpc3QoZGF0YXNldHNfbiA9IDApKSAlPiUgCiAgZ2dwbG90KCkgKyBnZW9tX3NmKGFlcyhmaWxsID0gZGF0YXNldHNfbiksbHdkID0gMCkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJibHVlIiwgaGlnaD0icmVkIikgKwogIHRoZW1lX2J3KCkgCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KcDIKYGBgCgoKYGBge3J9CnRlbXAgPC0gZ2FkbTM2X2xldmVsc18yICU+JQogICBsZWZ0X2pvaW4oCiAgIGxoc19sb25nICAlPiUgY291bnQoZ2lkLCBkYXRhc2V0KSAlPiUgcmVuYW1lKEdJRF8yPWdpZCkgI3RoZXJlIGFyZSBzdGlsbCBkdXBlIGdlb25hbWVzIHdpa2lkYXRhIHRvIGdpZCBtYXRjaGVzIHRoYXQgbmVlZCB0byBiZSBmaXhlZCBnZW9uYW1laWQsIHdpa2lkYXRhX2lkLCAKKSAKCnRlbXBfd2lkZSA8LSB0ZW1wICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGRwbHlyOjpzZWxlY3QoQ291bnRyeT1OQU1FXzAsIEFkbWluMT1OQU1FXzEsIEFkbWluMj1OQU1FXzIsIGRhdGFzZXQsIG4pICU+JSBkaXN0aW5jdCgpICU+JSBwaXZvdF93aWRlciggaWRfY29scyA9IENvdW50cnk6QWRtaW4yLCBuYW1lc19mcm9tID0gZGF0YXNldCwKICB2YWx1ZXNfZnJvbSA9IG4sIHZhbHVlc19maWxsID0gTlVMTCwgdmFsdWVzX2ZuID0gTlVMTCkgJT4lIG11dGF0ZSh0b3RhbCA9IHJvd1N1bXMoLlstYygxLDIsMyldLCBuYS5ybSA9IFQpKQoKdGVtcF93aWRlICU+JSBmaWx0ZXIodG90YWw+MCkgJT4lIERUOjpkYXRhdGFibGUob3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwLCBhdXRvV2lkdGggPSBUUlVFKSkKCmBgYAoKIyMgQ291bnRyeSBEYXRhIEF2YWlsYWJpbGl0eSBvZiBUZXN0aW5nCgpgYGB7cn0KCmxoc19sb25nX3BsYWNlX3NvdXJjZXNfdGVzdGluZyA8LSBsaHNfbG9uZyAgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGdpZCwgIGdlb25hbWVpZCwgd2lraWRhdGFfaWQsIGRhdGVfYXNkYXRlLCBjb25maXJtZWQsIHRlc3RlZF9wZW9wbGUsIHRlc3RlZF9zYW1wbGVzKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGdpZCwgIGdlb25hbWVpZCwgd2lraWRhdGFfaWQsIGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGVfaWYoaXMubnVtZXJpYywgbWF4LCBuYS5ybT1UKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcighZHVwbGljYXRlZChkYXRlX2FzZGF0ZSkpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5ncm91cCgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGxpc3Qofm5hX2lmKC4sIC1JbmYpKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGVfaWYoaXMubnVtZXJpYywgbGlzdCh+bmFfaWYoLiwgSW5mKSkpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHBlcmNlbnRfb2ZfZGF5c193aXRob3V0X3Rlc3Rpbmc9IWlzLm5hKGRhdGVfYXNkYXRlKSAmIChpcy5uYSh0ZXN0ZWRfcGVvcGxlKSAmIGlzLm5hKHRlc3RlZF9zYW1wbGVzKSAgKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGdpZCwgIGdlb25hbWVpZCwgd2lraWRhdGFfaWQpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJjZW50X29mX2RheXNfd2l0aG91dF90ZXN0aW5nPXN1bShwZXJjZW50X29mX2RheXNfd2l0aG91dF90ZXN0aW5nLCBuYS5ybT1UKS9uKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHBlcmNlbnRfb2ZfZGF5c193aXRoX3Rlc3Rpbmc9IDEtcGVyY2VudF9vZl9kYXlzX3dpdGhvdXRfdGVzdGluZykgCgoKcDBfdGVzdGluZyA8LSBnYWRtMzZfbGV2ZWxzXzAgJT4lIAogICAgICBsZWZ0X2pvaW4obGhzX2xvbmdfcGxhY2Vfc291cmNlc190ZXN0aW5nICU+JSBkcGx5cjo6c2VsZWN0KGdpZD1naWQsIHBlcmNlbnRfb2ZfZGF5c193aXRoX3Rlc3RpbmcpICU+JSAgbGVmdF9qb2luKCBnYWRtMzZfbGV2ZWxzXzAgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OnNlbGVjdChnaWQ9R0lEXzAsIE5BTUVfMCkgICU+JSBkaXN0aW5jdCgpICApCiAgICAgICAgICAgICAgICApICU+JQogICAgICAjcmVwbGFjZV9uYShsaXN0KGRhdGFzZXRzX24gPSAwKSkgJT4lIAogICAgICBnZ3Bsb3QoKSArIGdlb21fc2YoYWVzKGZpbGwgPSBwZXJjZW50X29mX2RheXNfd2l0aF90ZXN0aW5nKSkgKwogICAgICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0icmVkIiwgaGlnaD0iZ3JlZW4iKSArCiAgICAgIHRoZW1lX2J3KCkgKyBnZ3RpdGxlKCJQZXJjZW50IG9mIERheXMgd2l0aCBUZXN0aW5nIGNvdW50cyIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KcDBfdGVzdGluZwpgYGAKYGBge3Isd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KcDFfdGVzdGluZyA8LSBnYWRtMzZfbGV2ZWxzXzEgJT4lIAogIGxlZnRfam9pbihsaHNfbG9uZ19wbGFjZV9zb3VyY2VzX3Rlc3RpbmcgJT4lIGRwbHlyOjpzZWxlY3QoZ2lkPWdpZCwgcGVyY2VudF9vZl9kYXlzX3dpdGhfdGVzdGluZykgJT4lICBsZWZ0X2pvaW4oIGdhZG0zNl9sZXZlbHNfMSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBkcGx5cjo6c2VsZWN0KGdpZD1HSURfMSwgTkFNRV8xKSAlPiUgZGlzdGluY3QoKSAgKQogICkgJT4lCiAgI3JlcGxhY2VfbmEobGlzdChkYXRhc2V0c19uID0gMCkpICU+JSAKICBnZ3Bsb3QoKSArIGdlb21fc2YoYWVzKGZpbGwgPSBwZXJjZW50X29mX2RheXNfd2l0aF90ZXN0aW5nKSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJyZWQiLCBoaWdoPSJncmVlbiIpICsKICB0aGVtZV9idygpICArIGdndGl0bGUoIlBlcmNlbnQgb2YgRGF5cyB3aXRoIFRlc3RpbmcgY291bnRzIikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQpwMV90ZXN0aW5nCmBgYAoKIyBEYXRhIEF2YWlsYWJpbGl0eSBhbmQgSW50ZXJwb2xhdGlvbiBvdmVyIFRpbWUKCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CgojdGVzdCA8LSBsaHNfbG9uZyAlPiUgZ3JvdXBfYnkoZGF0YXNldCwgZ2lkLCBnZW9uYW1laWQsIHdpa2lkYXRhX2lkLCBkYXRlX2FzZGF0ZSkgJT4lIHN1bW1hcml6ZShuPW4oKSkKCmFsbF9uYSA8LSBmdW5jdGlvbih4KSBhbnkoIWlzLm5hKHgpKSAjaHR0cHM6Ly9pbnRlbGxpcGFhdC5jb20vY29tbXVuaXR5LzEyOTk5L3JlbW92ZS1jb2x1bW5zLWZyb20tZGF0YWZyYW1lLXdoZXJlLWFsbC12YWx1ZXMtYXJlLW5hCgojYmluZyBsb29rcyBvZmYgYnkgYSBkYXkgZnJvbSB0aGUgb3RoZXIgb25lcwpsaHNfd2lkZV9xY29kZSA8LSBsaHNfbG9uZyAlPiUgCiAgICAgICAgICAgICAgICAgIGZpbHRlcighaXMubmEod2lraWRhdGFfaWQpICYgIWlzLm5hKGRhdGVfYXNkYXRlKSkgJT4lCiAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGdpZCwgZ2VvbmFtZWlkLCB3aWtpZGF0YV9pZCwgZGF0ZV9hc2RhdGUpICU+JSAgbXV0YXRlKGNvbmZpcm1lZF92YXI9dmFyKGNvbmZpcm1lZCwgbmEucm09VCksIGRlYXRoc192YXI9dmFyKGRlYXRocywgbmEucm09VCkpICU+JSB1bmdyb3VwKCkgJT4lCiAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoZGF0YXNldCwgZ2lkLCBnZW9uYW1laWQsIHdpa2lkYXRhX2lkLCBkYXRlX2FzZGF0ZSxjb25maXJtZWQsIGRlYXRocywgdGVzdGVkX3NhbXBsZXMsIHRlc3RlZF9wZW9wbGUpICU+JQogICAgICAgICAgICAgICAgICBncm91cF9ieShkYXRhc2V0LCBnaWQsIGdlb25hbWVpZCwgd2lraWRhdGFfaWQsIGRhdGVfYXNkYXRlKSAlPiUgIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLG1heCxuYS5ybT1UKSAlPiUgdW5ncm91cCgpICU+JSAjdGhpcyBpcyBhIGhhY2ssIHdlIHNob3VsZCBoYXZlIGR1cGVzIHdpdGhpbiBkYXRhc2V0cwogICAgICAgICAgICAgICAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gZGF0YXNldCwgdmFsdWVzX2Zyb20gPSBjKGNvbmZpcm1lZCwgZGVhdGhzLCB0ZXN0ZWRfc2FtcGxlcywgdGVzdGVkX3Blb3BsZSkgKSAlPiUgCiAgICAgICAgICAgICAgICAgIG11dGF0ZV9pZihpcy5udW1lcmljLCBsaXN0KH5uYV9pZihhYnMoLiksIEluZikpKSAlPiUgI2h0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEyMTg4NTA5L2NsZWFuaW5nLWluZi12YWx1ZXMtZnJvbS1hbi1yLWRhdGFmcmFtZQogICAgICAgICAgICAgICAgICBzZWxlY3RfaWYoYWxsX25hKSAKCmRpbShsaHNfd2lkZV9xY29kZSkgIzgyLDE1NyA4MmsgcGxhY2UvZGF5IG9ic2VydmF0aW9ucwoKbGVuZ3RoKHVuaXF1ZShsaHNfd2lkZV9xY29kZSR3aWtpZGF0YV9pZCkpICMzNjk3ICNhbG1vc3QgNGsgCgp0ZXN0IDwtIGxoc193aWRlX3Fjb2RlICU+JSBkcGx5cjo6c2VsZWN0KHN0YXJ0c193aXRoKCJjb25maXJtZWQiKSkgJT4lIGRpc3RpbmN0KCkgCiNjb3IodGVzdCwgdXNlPSJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQoKbGhzX2xvbmdfbWVkaWFuIDwtIGxoc19sb25nICU+JSBncm91cF9ieShnaWQsIGdlb25hbWVpZCwgd2lraWRhdGFfaWQsIGRhdGVfYXNkYXRlKSAlPiUgc3VtbWFyaXplX2lmKGlzLm51bWVyaWMsIG1lZGlhbiwgbmEucm09VCkgJT4lIGRwbHlyOjpzZWxlY3QoLWVuZHNfd2l0aCgiX2ZkIikpICU+JSAjd2UgdGFrZSB0aGUgbWVkaWFuIGFjcm9zcyBvYnNlcnZhdGlvbnMKICAgICAgICAgICAgICAgICAgIG11dGF0ZShDRlI9ZGVhdGhzL2NvbmZpcm1lZCkKI2RpbShsaHNfbG9uZ19tZWRpYW4pCiNzdW1tYXJ5KGxoc19sb25nX21lZGlhbikKYGBgCgpIZXJlIHdlIGRvIHRoZSBhY3R1YWwgaW50ZXJwb2xhdGlvbi4gRm9yIGVhY2ggaW5kaXZpZHVhbCBsb2NhdGlvbi1kYXRhc2V0LCB3ZSBmaXQgYSBwaWVjZXdpc2UgbGluZWFyIG1vZGVsIG92ZXIgdGltZSwgYW5kIHRoZW4gdXNlIHRoYXQgdG8gYXZlcmFnZSBvdmVyIGRheSB0byBkYXkgbm9pc2UgYW5kIGludGVycG9sYXRlIGJldHdlZW4gb2JzZXJ2YXRpb25zLiBCZWNhdXNlIHRoaXMgaXMgaW4gbG9nIHNwYWNlLCB0aGUgc2xvcGUgb2YgdGhhdCBsaW5lIGlzIHRoZSBkYXkgb24gZGF5IHBlcmNlbnQgaW5jcmVhc2UgaW4gdGhlIGNvdW50LiBXZSBmaW5pc2ggYnkgZml0dGluZyBhIHBpZWNld2lzZSBpbnRlcmNlcHQgbW9kZWwgdG8gdGhvc2Ugc2xvcGVzIHRvIGdldCBhIHNpbmdsZSBkYWlseSBlc3RpbWF0ZSBvZiBob3cgbXVjaCB0aGUgY291bnQgaXMgaW5jcmVhc2luZy4gRGF0YXNldHMgYXJlIGFibGUgdG8gZGlzYWdyZWUgaW4gbG90cyBvZiBkaWZmZXJlbnQgd2F5cyBhbmQgd2Ugc3RpbGwgcmVjb3ZlciBhIGNvcnJlY3QgcmF0ZSBvZiBjaGFuZ2UuCgojIyBJbnRlcnBvbGF0aW9uIG9mIENvdW50cwoKVG8gZWFjaCBpbmRpdmlkdWFsIGRhdGFzZXQtbG9jYXRpb24gc2VyaWVzLCB3ZSBmaXQgYSBwaWVjZXdpc2UgbGluZWFyIHRyZW5kLiBFYWNoIHNlZ21lbnQgaXMgcmVxdWlyZWQgdG8gaGF2ZSBhdCBsZWFzdCAzIG9ic2VydmF0aW9ucywgYnV0IG90aGVyd2lzZSB3ZSBtYWtlIG5vIG90aGVyIGNvbnN0cmFpbnRzLiBUaGlzIGFsbG93cyB1cyB0byBmbGV4aWJseSBmaXQgbGluZWFyIHNlZ21lbnRzIGFzIHdlbGwgYXMgdGlnaHQgY3VydmVzLiBXZSBhbHNvIGFsbG93IGZvciBzdHJ1Y3R1cmFsIGJyZWFrcyB3aGVyZSB0aGUgc2VyaWVzIHN0b3BzLCBoYXMgYSBzdHJ1Y3R1cmFsIHNoaWZ0IHVwIG9yIGRvd24gYmVjYXVzZSBzYXkgYSBjaGFuZ2UgaW4gcmVwb3J0aW5nIHJ1bGVzLCBidXQgb3RoZXIgdGhlbiBvdGhlcndpc2UgY29udGludWVzIGFzIG5vcm1hbC4gV2UgdGFrZSB0aGUgbGluZWFyIHRyZW5kIGZpdCBhcyBvdXIgYmVzdCBlc3RpbWF0ZSBhdCBlYWNoIHBvaW50LiBUaGlzIGF2ZXJhZ2VzIG92ZXIgZGF5IHRvIGRheSBub2lzZSwgZS5nLiB1bmRlciByZXBvcnRpbmcgb24gdGhlIHdlZWtlbmQuIEl0IGFsc28gYWxsb3dzIHVzIHRvIGludGVycG9sYXRlIGJldHdlZW4gb2JzZXJ2YXRpb25zIHdoZXJlIHRoZXJlIGlzIG1pc3NpbmduZXNzIGluIHRoZSBzZXJpZXMgYnV0IHdlIGhhdmUgcmVhc29uYWJsZSBiZWxpZWZzIHRoZSB0cnVlIG1lYXN1cmUgY29udGludWVkIGxpbmVhcmx5IGJldHdlZW4gdGhlIG9ic2VydmVkIHBvaW50cy4KCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KCmRhdGFzZXRfcGxhY2VzIDwtIGxoc19sb25nX2NsZWFuICU+JSBkcGx5cjo6c2VsZWN0KGRhdGFzZXRfZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCkgJT4lIGRpc3RpbmN0KCkgJT4lIHB1bGwoZGF0YXNldF9naWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKQpsaWJyYXJ5KHBhcnR5KQp0ZW1wX2xpc3QxIDwtIGxpc3QoKQpmb3IocSBpbiBkYXRhc2V0X3BsYWNlcyAgKXsKICAgICAgdHJ5KHsKICAgICAgICB0ZW1wIDwtIE5VTEwKICAgICAgICB0ZW1wIDwtIGxoc19sb25nX2NsZWFuICU+JQogICAgICAgICAgICAgICAgZmlsdGVyKGRhdGFzZXRfZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCAlaW4lIHEpICU+JQogICAgICAgICAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lCgogICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2c9bG9nKGNvbmZpcm1lZCkpICU+JQogICAgICAgICAgICAgICAgbXV0YXRlKGRlYXRoc19sb2c9bG9nKGRlYXRocykpICU+JQogICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbG9nPWxvZyh0ZXN0ZWRfcGVvcGxlKSkgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3NhbXBsZXNfbG9nPWxvZyh0ZXN0ZWRfc2FtcGxlcykpIAogICAgICAgICAgCiAgICAgICAgaWYobnJvdyh0ZW1wKT09MCl7bmV4dCgpfQogICAgICAgIAogICAgICAgIHRlbXAgPC0gdGVtcCAlPiUgZXhwYW5kKGRhdGFzZXQsIGdpZF9nZW9uYW1laWRfd2lraWRhdGFfaWQsIGdpZCwgZ2VvbmFtZWlkLHdpa2lkYXRhX2lkLCBkYXRlX2FzZGF0ZT1taW4oZGF0ZV9hc2RhdGUpOm1heChkYXRlX2FzZGF0ZSkgJT4lIGFzX2RhdGUoKSApICU+JSAKICAgICAgICAgICAgICAgICBmdWxsX2pvaW4odGVtcCkgJT4lIAogICAgICAgICAgICAgICAgIG11dGF0ZShkYXRlX2FzbnVtZXJpYz0gYXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkgKSAlPiUgCiAgICAgICAgICAgICAgICAgYXJyYW5nZShkYXRlX2FzbnVtZXJpYykgJT4lCiAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9ub25taXNzaW5nX2NvdW50ICAgICA9ICghaXMubmEoY29uZmlybWVkKSkgJT4lIGN1bXN1bSgpICkgJT4lCiAgICAgICAgICAgICAgICAgbXV0YXRlKGRlYXRoc19ub25taXNzaW5nX2NvdW50ICAgICA9ICghaXMubmEoZGVhdGhzKSkgJT4lIGN1bXN1bSgpICkgJT4lCiAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbm9ubWlzc2luZ19jb3VudCAgICAgPSAoIWlzLm5hKHRlc3RlZF9wZW9wbGUpKSAlPiUgY3Vtc3VtKCkgKSAlPiUKICAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3NhbXBsZXNfbm9ubWlzc2luZ19jb3VudCAgICAgPSAoIWlzLm5hKHRlc3RlZF9zYW1wbGVzKSkgJT4lIGN1bXN1bSgpICkgJT4lCiAgICAgICAgCiAgICAgICAgICAgICAgICAgYXJyYW5nZSgtZGF0ZV9hc251bWVyaWMpICU+JQogICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbm9ubWlzc2luZ19jb3VudF9yZXZlcnNlZCAgICAgPSAoIWlzLm5hKGNvbmZpcm1lZCkpICU+JSBjdW1zdW0oKSApICU+JQogICAgICAgICAgICAgICAgIG11dGF0ZShkZWF0aHNfbm9ubWlzc2luZ19jb3VudF9yZXZlcnNlZCAgICAgPSAoIWlzLm5hKGRlYXRocykpICU+JSBjdW1zdW0oKSApICU+JQogICAgICAgICAgICAgICAgIG11dGF0ZSh0ZXN0ZWRfcGVvcGxlX25vbm1pc3NpbmdfY291bnRfcmV2ZXJzZWQgICAgID0gKCFpcy5uYSh0ZXN0ZWRfcGVvcGxlKSkgJT4lIGN1bXN1bSgpICkgJT4lCiAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9zYW1wbGVzX25vbm1pc3NpbmdfY291bnRfcmV2ZXJzZWQgICAgID0gKCFpcy5uYSh0ZXN0ZWRfc2FtcGxlcykpICU+JSBjdW1zdW0oKSApICU+JSAKICAgICAgICAgICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAKCiAgICAgICAgdHJ5Q2F0Y2goeyAgCiAgICAgICAgICBpZihzdW0oIWlzLm5hKHRlbXAkY29uZmlybWVkX2xvZykpPj0zKXsgI25lZWQgYXQgbGVhc3QgMyBwb2ludHMKICAgICAgICAgICAgdHJlZV9jb25maXJtZWQgPC0gcGFydHk6Om1vYihjb25maXJtZWRfbG9nIH4gMSArIGRhdGVfYXNudW1lcmljICAgIHwgZGF0ZV9hc251bWVyaWMgLCBjb250cm9sID0gbW9iX2NvbnRyb2wobWluc3BsaXQgPSAzLCBhbHBoYT0uMiksIGRhdGEgPSB0ZW1wLCAgbW9kZWwgPSBsaW5lYXJNb2RlbCkgICMgKyBJKGRhdGVfYXNudW1lcmljXjIpICAKICAgICAgICAgICAgdGVtcCRjb25maXJtZWRfbG9nX3lfaGF0IDwtIHByZWRpY3QoIHRyZWVfY29uZmlybWVkLCBuZXdkYXRhPXRlbXAgLCB0eXBlID0gYygicmVzcG9uc2UiKSApCiAgICAgICAgICAgIHRlbXAkY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIgPC0gIHByZWRpY3QoIHRyZWVfY29uZmlybWVkLCBuZXdkYXRhPXRlbXAgLCB0eXBlID0gYygibm9kZSIpKQogICAgICAgICAgICB0ZW1wIDwtIHRlbXAgJT4lIAogICAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nX3lfaGF0ICAgICAgID1pZmVsc2UoY29uZmlybWVkX25vbm1pc3NpbmdfY291bnQ+MCAmIGNvbmZpcm1lZF9ub25taXNzaW5nX2NvdW50X3JldmVyc2VkPjAsY29uZmlybWVkX2xvZ195X2hhdCxOQSkpICU+JSAjb25seSBpbnRlcnBvbGF0ZSB3aXRoaW4gdGhlIG9ic2VydmVkIGRhdGEsIG5ldmVyIGJlZm9yZSBvciBhZnRlcgogICAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcj1pZmVsc2UoY29uZmlybWVkX25vbm1pc3NpbmdfY291bnQ+MCAmIGNvbmZpcm1lZF9ub25taXNzaW5nX2NvdW50X3JldmVyc2VkPjAsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIsTkEpKSAlPiUgI29ubHkgaW50ZXJwb2xhdGUgd2l0aGluIHRoZSBvYnNlcnZlZCBkYXRhLCBuZXZlciBiZWZvcmUgb3IgYWZ0ZXIKCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpICU+JQogICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc251bWVyaWMpICU+JQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nX3lfaGF0X3Nsb3BlPXRzaWJibGU6OmRpZmZlcmVuY2UoY29uZmlybWVkX2xvZ195X2hhdCkpICU+JSAKICAgICAgICAgICAgICAgICAgICBmaWxsKGNvbmZpcm1lZF9sb2dfeV9oYXRfc2xvcGUsIC5kaXJlY3Rpb249InVwIikgJT4lIAogICAgICAgICAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IHJvdW5kKChleHAoY29uZmlybWVkX2xvZ195X2hhdF9zbG9wZSktMSkqMTAwLDIpKSAgJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2dfeV9oYXQ9aWZlbHNlKGNvbmZpcm1lZF9sb2dfeV9oYXQ8MCxOQSwgY29uZmlybWVkX2xvZ195X2hhdCkpCiAgICAgICAgICB9CiAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7fSkKICAgICAgICAKICAgICAgICB0cnlDYXRjaCh7ICAKICAgICAgICAgIGlmKHN1bSghaXMubmEodGVtcCRkZWF0aHNfbG9nKSk+PTMpeyAjbmVlZCBhdCBsZWFzdCAzIHBvaW50cwogICAgICAgICAgICB0cmVlX2RlYXRocyA8LSBwYXJ0eTo6bW9iKGRlYXRoc19sb2cgfiAxICsgZGF0ZV9hc251bWVyaWMgICAgfCBkYXRlX2FzbnVtZXJpYyAsIGNvbnRyb2wgPSBtb2JfY29udHJvbChtaW5zcGxpdCA9IDMsIGFscGhhPS4yKSwgZGF0YSA9IHRlbXAsICBtb2RlbCA9IGxpbmVhck1vZGVsKSAgIyArIEkoZGF0ZV9hc251bWVyaWNeMikgICAgCiAgICAgICAgICAgIHRlbXAkZGVhdGhzX2xvZ195X2hhdCA8LSBwcmVkaWN0KCB0cmVlX2RlYXRocywgbmV3ZGF0YT10ZW1wICwgdHlwZSA9IGMoInJlc3BvbnNlIikgKQogICAgICAgICAgICB0ZW1wJGRlYXRoc19sb2dfZ3JvdXBfbnVtYmVyIDwtICBwcmVkaWN0KCB0cmVlX2RlYXRocywgbmV3ZGF0YT10ZW1wICwgdHlwZSA9IGMoIm5vZGUiKSkKICAgICAgICAgICAgdGVtcCA8LSB0ZW1wICU+JSAKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZGVhdGhzX2xvZ195X2hhdD1pZmVsc2UoZGVhdGhzX25vbm1pc3NpbmdfY291bnQ+MCAmIGRlYXRoc19ub25taXNzaW5nX2NvdW50X3JldmVyc2VkPjAsZGVhdGhzX2xvZ195X2hhdCxOQSkpICU+JSAjb25seSBpbnRlcnBvbGF0ZSB3aXRoaW4gdGhlIG9ic2VydmVkIGRhdGEsIG5ldmVyIGJlZm9yZQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShkZWF0aHNfbG9nX2dyb3VwX251bWJlcj1pZmVsc2UoZGVhdGhzX25vbm1pc3NpbmdfY291bnQ+MCAmIGRlYXRoc19ub25taXNzaW5nX2NvdW50X3JldmVyc2VkPjAsZGVhdGhzX2xvZ19ncm91cF9udW1iZXIsTkEpKSAlPiUgI29ubHkgaW50ZXJwb2xhdGUgd2l0aGluIHRoZSBvYnNlcnZlZCBkYXRhLCBuZXZlciBiZWZvcmUKCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoZGVhdGhzX2xvZ19ncm91cF9udW1iZXIpICU+JSAKICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRhdGVfYXNudW1lcmljKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGRlYXRoc19sb2dfeV9oYXRfc2xvcGU9dHNpYmJsZTo6ZGlmZmVyZW5jZShkZWF0aHNfbG9nX3lfaGF0KSkgJT4lCiAgICAgICAgICAgICAgICAgICAgZmlsbChkZWF0aHNfbG9nX3lfaGF0X3Nsb3BlLCAuZGlyZWN0aW9uPSJ1cCIpICU+JQogICAgICAgICAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IHJvdW5kKChleHAoZGVhdGhzX2xvZ195X2hhdF9zbG9wZSktMSkqMTAwLDIpKSAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZGVhdGhzX2xvZ195X2hhdD1pZmVsc2UoZGVhdGhzX2xvZ195X2hhdDwwLE5BLCBkZWF0aHNfbG9nX3lfaGF0KSkgI3JlamVjdCBhbnkgd2hlcmUgdGhlIHByZWRpY3Rpb24gaXMgbGVzcyB0aGFuIDEgZnVsbCBjYXNlCiAgICAgICAgICB9CiAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7fSkKICAgICAgICAKICAgICAgICB0cnlDYXRjaCh7ICAKICAgICAgICAgIGlmKHN1bSghaXMubmEodGVtcCR0ZXN0ZWRfcGVvcGxlX2xvZykpPj0zKXsgI25lZWQgYXQgbGVhc3QgMyBwb2ludHMKICAgICAgICAgICAgdHJlZV90ZXN0ZWRfcGVvcGxlIDwtIHBhcnR5Ojptb2IodGVzdGVkX3Blb3BsZV9sb2cgfiAxICsgZGF0ZV9hc251bWVyaWMgICAgfCBkYXRlX2FzbnVtZXJpYyAsIGNvbnRyb2wgPSBtb2JfY29udHJvbChtaW5zcGxpdCA9IDMsIGFscGhhPS4yKSwgZGF0YSA9IHRlbXAsICBtb2RlbCA9IGxpbmVhck1vZGVsKSAgIyArIEkoZGF0ZV9hc251bWVyaWNeMikgICAKICAgICAgICAgICAgdGVtcCR0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCA8LSBwcmVkaWN0KCB0cmVlX3Rlc3RlZF9wZW9wbGUsIG5ld2RhdGE9dGVtcCAsIHR5cGUgPSBjKCJyZXNwb25zZSIpICkKICAgICAgICAgICAgdGVtcCR0ZXN0ZWRfcGVvcGxlX2xvZ19ncm91cF9udW1iZXIgPC0gIHByZWRpY3QoIHRyZWVfdGVzdGVkX3Blb3BsZSwgbmV3ZGF0YT10ZW1wICwgdHlwZSA9IGMoIm5vZGUiKSkKICAgICAgICAgICAgdGVtcCA8LSB0ZW1wICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQ9aWZlbHNlKHRlc3RlZF9wZW9wbGVfbm9ubWlzc2luZ19jb3VudD4wICYgdGVzdGVkX3Blb3BsZV9ub25taXNzaW5nX2NvdW50X3JldmVyc2VkPjAsdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsTkEpKSAlPiUgI29ubHkgaW50ZXJwb2xhdGUgd2l0aGluIHRoZSBvYnNlcnZlZCBkYXRhLCBuZXZlciBiZWZvcmUKICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3Blb3BsZV9sb2dfZ3JvdXBfbnVtYmVyPWlmZWxzZSh0ZXN0ZWRfcGVvcGxlX25vbm1pc3NpbmdfY291bnQ+MCAmIHRlc3RlZF9wZW9wbGVfbm9ubWlzc2luZ19jb3VudF9yZXZlcnNlZD4wLHRlc3RlZF9wZW9wbGVfbG9nX2dyb3VwX251bWJlcixOQSkpICU+JSAjb25seSBpbnRlcnBvbGF0ZSB3aXRoaW4gdGhlIG9ic2VydmVkIGRhdGEsIG5ldmVyIGJlZm9yZQogICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KHRlc3RlZF9wZW9wbGVfbG9nX2dyb3VwX251bWJlcikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc251bWVyaWMpICU+JQogICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZSh0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9zbG9wZT10c2liYmxlOjpkaWZmZXJlbmNlKHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0KSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIGZpbGwodGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfc2xvcGUsIC5kaXJlY3Rpb249InVwIikgJT4lIHVuZ3JvdXAoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSByb3VuZCgoZXhwKHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3Nsb3BlKS0xKSoxMDAsMikpICU+JQogICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZSh0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdD1pZmVsc2UodGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQ8MCxOQSwgdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQpKSAjcmVqZWN0IGFueSB3aGVyZSB0aGUgcHJlZGljdGlvbiBpcyBsZXNzIHRoYW4gMSBmdWxsIGNhc2UKICAgICAgICAgIH0KICAgICAgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHt9KQogICAgICAgIAogICAgICAgIHRlbXBfbGlzdDFbW3EgXV0gPC0gdGVtcAogIAogICAgICB9KQp9Cmxoc19sb25nX2NsZWFuX2ltcHV0ZWQxIDwtIGJpbmRfcm93cyh0ZW1wX2xpc3QxKQpkaW0obGhzX2xvbmdfY2xlYW5faW1wdXRlZDEpICM1MDAsNzg2ICNiaWdnZXIgYmVjYXVzZSB3ZSdyZSBpbnRlcnBvbGF0aW5nIG5vdwoKI3J0MSA8LSBycGFydChmb3JtdWxhID0gY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IGRhdGVfYXNudW1lcmljLCBkYXRhPXRlc3QpCiNpbnRlcnBvbGF0ZWQgPSBkYXRhLmZyYW1lKGRhdGVfYXNudW1lcmljPW1pbih0ZXN0JGRhdGVfYXNudW1lcmljKTptYXgodGVzdCRkYXRlX2FzbnVtZXJpYykgKQojaW50ZXJwb2xhdGVkJGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgPC0gIHByZWRpY3QocnQxLCBuZXdkYXRhPWludGVycG9sYXRlZCkKI2ludGVycG9sYXRlZCRkYXRlX2FzZGF0ZSA8LSBhcy5EYXRlKGludGVycG9sYXRlZCRkYXRlX2FzbnVtZXJpYykKCnBsYWNlcyA8LSBsaHNfbG9uZ19jbGVhbiAlPiUgZHBseXI6OnNlbGVjdChnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKSAlPiUgZGlzdGluY3QoKSAlPiUgcHVsbChnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKQoKbGlicmFyeShycGFydCkKbWluc3BsaXQ9NgptaW5idWNrZXQ9Mwp0ZW1wX2xpc3QyIDwtIGxpc3QoKQpmb3IocSBpbiBwbGFjZXMgKXsKICBwcmludChxKQogIHRlbXAgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZDEgJT4lIAogICAgICAgICAgICAgICAgIGZpbHRlcihnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkICVpbiUgcSkgJT4lIAogICAgICAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc251bWVyaWMpIAogICAgCiAgICAgICAgICAKICB0cnlDYXRjaCh7ICAKICAgIHJ0MSA8LSBycGFydDo6cnBhcnQoZm9ybXVsYSA9IGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiBkYXRlX2FzbnVtZXJpYywKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT10ZW1wICU+JSBmaWx0ZXIoIWlzLm5hKGNvbmZpcm1lZF9sb2cpKSwgI3RvIGtlZXAgZnJvbSBmaXR0aW5nIHRvIGludGVycG9sYXRlIHNsb3BlcyB0aGF0IGFyZSBvdXQgb2YgZG9tYWluIGFuZCB1c3VhbGx5IHdyb25nLCByZXF1aXJlIGNvbmZpcm1lZCB0byBub3QgYmUgbWlzc2luZyBvciBuYQogICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gcnBhcnQuY29udHJvbChtaW5zcGxpdCA9IG1pbnNwbGl0LCBtaW5idWNrZXQ9bWluYnVja2V0KSkKICAgIHRlbXAkY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCA8LSAgcHJlZGljdChydDEsIG5ld2RhdGE9dGVtcCkgI3RoaXMgcHJlZGljdGlvbiBoZWxwZnVsbHkgdHJpZXMgdG8gaW1wdXRlIGJhY2t3YXJkcyBldmVuIGJlZm9yZSB0aGVyZSBhcmUgYW55IGRheSBpbiBhbnkgc2VyaWVzCiAgICAjV2UgbmVlZCB0byBudWtlIGl0IGlmIG5vIGRhdGEgZXhpc3QKICAgIHRlbXAgPC0gdGVtcCAlPiUKICAgICAgICAgICAgZ3JvdXBfYnkoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgICBtdXRhdGUoIGNvbmZpcm1lZF9ub25taXNzaW5nX2NvdW50X2RhdGFzZXRzPXN1bShjb25maXJtZWRfbm9ubWlzc2luZ19jb3VudD4wLG5hLnJtPVQpICkgJT4lCiAgICAgICAgICAgIG11dGF0ZSggY29uZmlybWVkX25vbm1pc3NpbmdfY291bnRfZGF0YXNldHNfcmV2ZXJzZWQ9c3VtKGNvbmZpcm1lZF9ub25taXNzaW5nX2NvdW50X3JldmVyc2VkPjAsbmEucm09VCkgKSAlPiUKICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQ9aWZlbHNlKGNvbmZpcm1lZF9ub25taXNzaW5nX2NvdW50X2RhdGFzZXRzPjAgJiBjb25maXJtZWRfbm9ubWlzc2luZ19jb3VudF9kYXRhc2V0c19yZXZlcnNlZD4wLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQsTkEpKSAgJT4lCiAgICAgIHVuZ3JvdXAoKQogICAgCiAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7fSkKICAKICB0cnlDYXRjaCh7ICAKICAgIHJ0MiA8LSBycGFydDo6cnBhcnQoZm9ybXVsYSA9IGRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiBkYXRlX2FzbnVtZXJpYywKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT10ZW1wICU+JSBmaWx0ZXIoIWlzLm5hKGRlYXRoc19sb2cpKSwKICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbCA9IHJwYXJ0LmNvbnRyb2wobWluc3BsaXQgPSBtaW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkpCiAgICB0ZW1wJGRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgPC0gIHByZWRpY3QocnQyLCBuZXdkYXRhPXRlbXApCiAgICB0ZW1wIDwtIHRlbXAgJT4lCiAgICAgICAgZ3JvdXBfYnkoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgIG11dGF0ZSggZGVhdGhzX25vbm1pc3NpbmdfY291bnRfZGF0YXNldHM9c3VtKGRlYXRoc19ub25taXNzaW5nX2NvdW50PjAsbmEucm09VCkgKSAlPiUKICAgICAgICBtdXRhdGUoIGRlYXRoc19ub25taXNzaW5nX2NvdW50X2RhdGFzZXRzX3JldmVyc2VkPXN1bShkZWF0aHNfbm9ubWlzc2luZ19jb3VudF9yZXZlcnNlZD4wLG5hLnJtPVQpICkgJT4lCiAgICAgICAgbXV0YXRlKGRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQ9aWZlbHNlKGRlYXRoc19ub25taXNzaW5nX2NvdW50X2RhdGFzZXRzPjAgJiBkZWF0aHNfbm9ubWlzc2luZ19jb3VudF9kYXRhc2V0c19yZXZlcnNlZD4wLGRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQsTkEpKSAlPiUKICAgICAgdW5ncm91cCgpCiAgICAgICAgCiAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7fSkKCiAgdHJ5Q2F0Y2goeyAgCiAgICBydDMgPC0gcnBhcnQ6OnJwYXJ0KGZvcm11bGEgPSB0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IGRhdGVfYXNudW1lcmljLAogICAgICAgICAgICAgICAgICAgIGRhdGE9dGVtcCAlPiUgZmlsdGVyKCFpcy5uYSh0ZXN0ZWRfcGVvcGxlX2xvZykpLAogICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBycGFydC5jb250cm9sKG1pbnNwbGl0ID0gbWluc3BsaXQsIG1pbmJ1Y2tldD1taW5idWNrZXQpKQogICAgdGVtcCR0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCA8LSAgcHJlZGljdChydDMsIG5ld2RhdGE9dGVtcCwgY29udHJvbCA9IHJwYXJ0LmNvbnRyb2wobWluc3BsaXQgPSBtaW5zcGxpdCwgbWluYnVja2V0PW1pbmJ1Y2tldCkpCiAgICB0ZW1wIDwtIHRlbXAgJT4lCiAgICAgICAgZ3JvdXBfYnkoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgIG11dGF0ZSggdGVzdGVkX3Blb3BsZV9ub25taXNzaW5nX2NvdW50X2RhdGFzZXRzPXN1bSh0ZXN0ZWRfcGVvcGxlX25vbm1pc3NpbmdfY291bnQ+MCxuYS5ybT1UKSApICU+JQogICAgICAgIG11dGF0ZSggdGVzdGVkX3Blb3BsZV9ub25taXNzaW5nX2NvdW50X2RhdGFzZXRzX3JldmVyc2VkPXN1bSh0ZXN0ZWRfcGVvcGxlX25vbm1pc3NpbmdfY291bnRfcmV2ZXJzZWQ+MCxuYS5ybT1UKSApICU+JQogICAgICAKICAgICAgICBtdXRhdGUodGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQ9aWZlbHNlKHRlc3RlZF9wZW9wbGVfbm9ubWlzc2luZ19jb3VudF9kYXRhc2V0cz4wICYgdGVzdGVkX3Blb3BsZV9ub25taXNzaW5nX2NvdW50X2RhdGFzZXRzX3JldmVyc2VkPjAsdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQsTkEpKSAgJT4lCiAgICAgIHVuZ3JvdXAoKQogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkge30pCiAgCiAgdGVtcF9saXN0MltbcSBdXSA8LSB0ZW1wCn0KbGhzX2xvbmdfY2xlYW5faW1wdXRlZDIgPC0gYmluZF9yb3dzKHRlbXBfbGlzdDIpCgpsaHNfbG9uZ19jbGVhbl9pbXB1dGVkIDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQyCmRpbShsaHNfbG9uZ19jbGVhbl9pbXB1dGVkKSAjNDE5OTEwICM0MTM0NzUgIzQwOCwzNjkgI3dlIGxvc2UgYW55d2l0aG91dCBxIGNvZGVzIGhlcmUKc2F2ZVJEUyhsaHNfbG9uZ19jbGVhbl9pbXB1dGVkLCAiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvbGhzX2xvbmdfY2xlYW5faW1wdXRlZC5SZHMiKQoKYGBgCgojIyMgRXhhbXBsZXMKCiMjIyMgQ2hpbmEKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KI0NoaW5hCiMiUTE0OCIKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMTQ4IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgpwX2ludGVycG9sYXRpb24wIDwtIHRlc3QgJT4lCiAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkNoaW5hIFExNDggQ29uZmlybWVkIikgKyBmYWNldF93cmFwKH5kYXRhc2V0ICAgKQoKYGBgCgpEYXRhIG9uIENoaW5hIHNob3dzIHZhcmlhdGlvbiBhY3Jvc3MgZGF0YXNldHMgZm9yIHdoZW4gdGhleSBzdGFydCBtZWFzdXJpbmcuIE9ubHkgdHdvIG9ic2VydmUgdGhlIHZlcnkgYmVnaW5uaW5nIG9mIHRoZSBvdXRicmVhay4gQWxsIG9mIHRoZSBkYXRhc2V0cyBzaG93IGEgZGlzY29udGludWl0eSB3aGVyZSByZXBvcnRpbmcgc3RhbmRhcmRzIG11c3QgaGF2ZSBjaGFuZ2VkLiBPdXIgbWV0aG9kIGF0dGVtcHRzIHRvIGJyaWRnZSB0aGF0IGdhcCBpbiAzIG9mIHRoZSBzZXJpZXMgYnV0IG5vdCB0d28gb3RoZXJzLgoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQpwX2ludGVycG9sYXRpb24wCmBgYAojIyMjIEl0YWx5IAoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQojSXRhbHkKIyJRMzgiCgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTM4IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgpwX2ludGVycG9sYXRpb24xIDwtIHRlc3QgJT4lCiAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkl0YWx5IFEzOCBDb25maXJtZWQiKSArIGZhY2V0X3dyYXAofmRhdGFzZXQgICApCgpgYGAKCkl0YWx5IGxpa2V3aXNlIHNob3dzIHZhcmlhdGlvbiBpbiB0aGUgc3RhcnQgb2YgcmVjb3JkaW5nIGFjcm9zcyBkYXRhc2V0cy4gVGhlcmUncyBhbHNvIHZhcmlhdGlvbiBpbiB0aGUgaW5pdGlhbCBzcGFyY2l0eS4gV2lraXBlZGlhIGlzIHN0cmFuZ2VseSBtaXNzaW5nIGRhdGEgaW4gdGhlIG1pZGRsZS4gT3VyIG1ldGhvZCBsaW5lYXJseSBpbnRlcnBvbGF0ZXMgaW50byB0aGF0IHNwYWNlIGluIGEgd2F5IGluIGEgd2F5IHdlIHByb2JhYmx5IGRvbid0IHdhbnQuCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CnBfaW50ZXJwb2xhdGlvbjEKYGBgCgojIyMjIEl0YWx5IAoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQojVVMKIyJRMzAiCgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTMwIikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgpwX2ludGVycG9sYXRpb24yIDwtIHRlc3QgJT4lCiAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIlVTIFEzMCBDb25maXJtZWQiKSArIGZhY2V0X3dyYXAofmRhdGFzZXQgICApCgpgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CnBfaW50ZXJwb2xhdGlvbjIKYGBgCgoKIyMjIyBOZXcgWW9yayBTdGF0ZQoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQojVVMKIyJRMzAiCgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTEzODQiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCnBfaW50ZXJwb2xhdGlvbjMgPC0gdGVzdCAlPiUKICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgICAgICAgICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgICAgICAgICAgZ2d0aXRsZSgiTmV3IFlvcmsgU3RhdGUgUTEzODQgQ29uZmlybWVkIikgKyBmYWNldF93cmFwKH5kYXRhc2V0ICAgKQoKYGBgCgoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQpwX2ludGVycG9sYXRpb24zCmBgYAoKIyMjIyBOZXcgWW9yayBDaXR5IChieSBjb3VudHkpCgpueXQgaGFzIGl0IGp1c3QgYnkgY2l0eSwgaXQgZG9lc24ndCBicmVhayBpdCBkb3duIGJ5IHRoZSBib3JvdWdocy4gQnV0IGJlY2F1c2UgZ2FkbSBkb2Vzbid0IGRvIGNpdGllcyB3ZSBkb24ndCBhc3NpZ24gaXQgYSBxY29kZS4KCnVzYWZhY3RzIGhhcyBpdCBhcyBOZXcgWW9yayBDb3VudHkgd2hpY2ggaXMgTmV3IFlvcmsgQ291bnR5IChNYW5oYXR0YW4pCgpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CiNCcm9va2x5biAoUTE4NDE5KQp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTg1NTk3NCIpICU+JSAgI25vIGhpdHM/CiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCnBfaW50ZXJwb2xhdGlvbjRhIDwtIHRlc3QgJT4lCiAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkJyb254IENvdW50eSAoUTg1NTk3NCkiKSArIGZhY2V0X3dyYXAofmRhdGFzZXQgICApICsgZ3VpZGVzKCBjb2xvciA9IEZBTFNFKQoKI1F1ZWVucyBDb3VudHksIE5ldyBZb3JrIFE1MTQyNTU5CnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRNTE0MjU1OSIpICU+JSAgI25vIGhpdHM/CiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCnBfaW50ZXJwb2xhdGlvbjRiIDwtIHRlc3QgJT4lCiAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIlF1ZWVucyBDb3VudHksIE5ldyBZb3JrIFE1MTQyNTU5IikgKyBmYWNldF93cmFwKH5kYXRhc2V0ICAgKSArIGd1aWRlcyggY29sb3IgPSBGQUxTRSkKCiNCcm9va2x5biBpcyBhcGFyZW50bHkgS2luZ3MgQ291bnR5IFExMTk4MDY5Mgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTExOTgwNjkyIikgJT4lICAjbm8gaGl0cz8KICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKcF9pbnRlcnBvbGF0aW9uNGMgPC0gdGVzdCAlPiUKICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgICAgICAgICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgICAgICAgICAgZ2d0aXRsZSgiQnJvb2tseW4gaXMgS2luZ3MgQ291bnR5IFExMTk4MDY5MiIpICsgZmFjZXRfd3JhcCh+ZGF0YXNldCAgICkgKyBndWlkZXMoIGNvbG9yID0gRkFMU0UpCgojIE1hbmhhdHRhbiBpcyBOZXcgWW9yayBDb3VudHkgUTUwMDQxNgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTUwMDQxNiIpICU+JSAgI25vIGhpdHM/CiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCnBfaW50ZXJwb2xhdGlvbjRkIDwtIHRlc3QgJT4lCiAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIk1hbmhhdHRhbiBpcyBOZXcgWW9yayBDb3VudHkgUTUwMDQxNiIpICsgZmFjZXRfd3JhcCh+ZGF0YXNldCAgICkgKyBndWlkZXMoIGNvbG9yID0gRkFMU0UpCgojU3RhdGVuIElzbGFuZCBpcyByaWNobW9uZCBjb3VudHkgUTExOTk3Nzg0CnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMTE5OTc3ODQiKSAlPiUgICNubyBoaXRzPwogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgpwX2ludGVycG9sYXRpb240ZSA8LSB0ZXN0ICU+JQogICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAgICAgICAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJTdGF0ZW4gSXNsYW5kICBSaWNobW9uZCBDb3VudHkgUTExOTk3Nzg0IikgKyBmYWNldF93cmFwKH5kYXRhc2V0ICAgKSArIGd1aWRlcyggY29sb3IgPSBGQUxTRSkKCmBgYAoKTm90ZSB0aGF0IENTU0UgaXMgY29uZmxhdGluZyBhbGwgb2YgTmV3IFlvcmsgQ2l0eSB3aXRoIE1hbmhhdHRhbi9OZXcgWW9yayBDb3VudHksIEJpbmcgaXMgdG9vIEkgdGhpbmsKCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02LHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KcF9pbnRlcnBvbGF0aW9uNGEgKyBwX2ludGVycG9sYXRpb240YiArIHBfaW50ZXJwb2xhdGlvbjRjICsgcF9pbnRlcnBvbGF0aW9uNGQgKyBwX2ludGVycG9sYXRpb240ZQpgYGAKCgoKIyMgUGxvdHMgYnkgQ291bnRyaWVzCgpgYGB7cn0KbGlicmFyeShkYXRhLnRhYmxlKQpnZW9uYW1lcyA8LSBmcmVhZCgiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvYWxsQ291bnRyaWVzLnR4dCIsIHNlcD0iXHQiKSAlPiUgbXV0YXRlX2lmKGlzLm51bWVyaWMsYXMuY2hhcmFjdGVyKSAlPiUgbXV0YXRlX2lmKGlzLmZhY3Rvcixhcy5jaGFyYWN0ZXIpCmRpbShnZW9uYW1lcykgIzEyLDAwNiw0MjYKCmdlb25hbWVzX3NtYWxsIDwtIGdlb25hbWVzICU+JSBkcGx5cjo6c2VsZWN0KGdlb25hbWVpZD1WMSwgbmFtZV90ZXh0PVYyKSAlPiUgaW5uZXJfam9pbiggbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgZHBseXI6OnNlbGVjdChnZW9uYW1laWQpICU+JSBkaXN0aW5jdCgpICkKZGltKGdlb25hbWVzX3NtYWxsKQoKYGBgCgojIyMgQ29uZmlybWVkCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KcF9jb25maXJtZWRfYnlfY291bnRyeSA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcighZ2lkICU+JSBzdHJfZGV0ZWN0KCJfIikgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oZ2VvbmFtZXNfc21hbGwgICkgJT4lIG11dGF0ZShuYW1lX3RleHQgJT4lIGFzLmZhY3RvcigpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2d0aXRsZSgiQ29uZmlybWVkIChsb2cpIGJ5IENvdW50cnkiKSArIGZhY2V0X3dyYXAofm5hbWVfdGV4dCAgICkgKyBndWlkZXMoIGNvbG9yID0gRkFMU0UpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAsICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKYGBgCgpgYGB7cn0KcF9jb25maXJtZWRfYnlfY291bnRyeQpgYGAKCiMjIyBEZWF0aHMKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KcF9kZWF0aHNfYnlfY291bnRyeSA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcighZ2lkICU+JSBzdHJfZGV0ZWN0KCJfIikgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oZ2VvbmFtZXNfc21hbGwgICkgJT4lIG11dGF0ZShuYW1lX3RleHQgJT4lIGFzLmZhY3RvcigpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2d0aXRsZSgiRGVhdGhzIChsb2cpIGJ5IENvdW50cnkiKSArIGZhY2V0X3dyYXAofm5hbWVfdGV4dCAgICkgKyBndWlkZXMoIGNvbG9yID0gRkFMU0UpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAsICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyfQpwX2RlYXRoc19ieV9jb3VudHJ5CmBgYAoKIyMjIFRlc3RzCgpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CnBfdGVzdGVkX3Blb3BsZV9ieV9jb3VudHJ5IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKCFnaWQgJT4lIHN0cl9kZXRlY3QoIl8iKSApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIGxlZnRfam9pbihnZW9uYW1lc19zbWFsbCAgKSAlPiUgbXV0YXRlKG5hbWVfdGV4dCAlPiUgYXMuZmFjdG9yKCkpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIlRlc3RzIChsb2cpIGJ5IENvdW50cnkiKSArIGZhY2V0X3dyYXAofm5hbWVfdGV4dCAgICkgKyBndWlkZXMoIGNvbG9yID0gRkFMU0UpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAsICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyfQpwX3Rlc3RlZF9wZW9wbGVfYnlfY291bnRyeQpgYGAKCgojIyBJbnRlcnBvbGF0aW9uIG9mIFJhdGUgb2YgQ2hhbmdlCgojIyBQbG90IENvbmZpcm1lZCBDdXJ2ZXMgZm9yIFNlbGVjdCBMb2NhdGlvbnMKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KCmxpYnJhcnkocGF0Y2h3b3JrKQpsaHNfbG9uZ19jbGVhbl9pbXB1dGVkIDwtIHJlYWRSRFMoICIvbWVkaWEvc2t5bmV0Mi85MDU4ODRmMC03NTQ2LTQyNzMtOTA2MS0xMmE3OTA4MzBiZWIvcndkX2dpdGh1Yl9wcml2YXRlL05FU1Njb3ZpZDE5L2RhdGFfdGVtcC9saHNfbG9uZ19jbGVhbl9pbXB1dGVkLlJkcyIpCmRpbShsaHNfbG9uZ19jbGVhbl9pbXB1dGVkKSAjNDUsNjA5ICMzMzcwNDMKCiN3ZSB3YW50IHRoZSBjb2xvcnMgdG8gYmUgY29uc2lzdGVudCBieSBkYXRhc2V0IHRvbyBidHcKCiMjIyMjCiNVU0EgUTMwCgojYnBfdGVtcCA8LSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPXRlbXBfZGYgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTMwIikpCiNjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlPWZpdHRlZC52YWx1ZXMoYnBfdGVtcCkKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGZpbHRlcih3aWtpZGF0YV9pZD09IlEzMCIpICU+JSAKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAgJT4lCiAgICAgICAgbXV0YXRlKGRhdGVfYXNudW1lcmljID0gZGF0ZV9hc2RhdGUgJT4lIGFzLm51bWVyaWMoKSApCgojcnQxIDwtIHJwYXJ0KGZvcm11bGEgPSBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gZGF0ZV9hc251bWVyaWMsIGRhdGE9dGVzdCkKI2ludGVycG9sYXRlZCA9IGRhdGEuZnJhbWUoZGF0ZV9hc251bWVyaWM9bWluKHRlc3QkZGF0ZV9hc251bWVyaWMpOm1heCh0ZXN0JGRhdGVfYXNudW1lcmljKSApCiNpbnRlcnBvbGF0ZWQkY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCA8LSAgcHJlZGljdChydDEsIG5ld2RhdGE9aW50ZXJwb2xhdGVkKQojaW50ZXJwb2xhdGVkJGRhdGVfYXNkYXRlIDwtIGFzLkRhdGUoaW50ZXJwb2xhdGVkJGRhdGVfYXNudW1lcmljKQoKcDBhIDwtIHRlc3QgJT4lCiAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgIGdndGl0bGUoIlVTQSBRMzAgQ29uZmlybWVkIikgIyArIGZhY2V0X3dyYXAofmRhdGFzZXQpIAoKcDBiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zICkgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIiAgKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiVVNBIFEzMCBDb25maXJtZWQiKSAjICsgZmFjZXRfd3JhcCh+ZGF0YXNldCkrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIENvbmZpcm1lZCIpCgojcDBhIC8gcDBiCgoKCiMjIyMjCiNDaGluYSBRMTQ4Cgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlExNDgiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQoKcDFhIDwtIHRlc3QgJT4lIApnZ3Bsb3QoKSArIAogICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJDaGluYSBRMTQ4IENvbmZpcm1lZCIpCgpwMWIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJDaGluYSBRMTQ4IENvbmZpcm1lZCIpKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSBDb25maXJtZWQiKQogICAKCiNwMWEgLyBwMWIKCiNJbmRpYQojIlE2NjgiCgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTY2OCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKCnAyYSA8LSB0ZXN0ICU+JQpnZ3Bsb3QoKSArIAogICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJbmRpYSBRNjY4IENvbmZpcm1lZCIpCgpwMmIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJbmRpYSBRNjY4IENvbmZpcm1lZCIpKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSBDb25maXJtZWQiKQogCiAgCiNwMmEgLyBwMmIKCgoKI0l0YWx5CiMiUTM4IgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlEzOCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKCnA0YSA8LSB0ZXN0ICU+JQpnZ3Bsb3QoKSArIAogICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJdGFseSBRMzggQ29uZmlybWVkIikKCnA0YiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkl0YWx5IFEzOCBDb25maXJtZWQiKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgQ29uZmlybWVkIikKICAgCiAgICAKI3A0YSAvIHA0YgoKCgojU291dGggS29yZWEKIyJRODg0IgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlE4ODQiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCgpwNWEgPC0gdGVzdCAlPiUKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiU291dGggS29yZWEgUTg4NCAgQ29uZmlybWVkIikKCnA1YiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIlNvdXRoIEtvcmVhIFE4ODQgQ29uZmlybWVkIikgKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSBDb25maXJtZWQiKQogICAKICAgIAojcDVhIC8gcDViCmBgYAoKCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYgLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KKHAwYSArIHAxYSArIHAyYSApIC8gKHAwYiArIHAxYiArIHAyYiApCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02ICx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CiggcDRhICsgcDVhKSAvICggcDRiICsgcDViKQpgYGAKCmBgYHtyfQoKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMTQzOSIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKCnAwYSA8LSB0ZXN0ICU+JQogICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICBnZ3RpdGxlKCJUZXhhcyBRMTQzOSBDb25maXJtZWQiKQoKcDBiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiVGV4YXMgUTE0MzkgQ29uZmlybWVkIikgKyB5bGltKDAsMTAwKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgQ29uZmlybWVkIikKCiNCZXhhcgojIlExNjg2MSIKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlExNjg2MSIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQpwMWEgPC0gdGVzdCAlPiUKICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiQmV4YXIgQ291bnR5IFExNjg2MSBDb25maXJtZWQiKQpwMWIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJCZXhhciBDb3VudHkgUTE2ODYxIENvbmZpcm1lZCIpICsgeWxpbSgwLDEwMCkrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIENvbmZpcm1lZCIpCgojQ2FsaWZvcm5pYQp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTk5IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCnAyYSA8LSB0ZXN0ICU+JQogICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICBnZ3RpdGxlKCJDYWxpZm9ybmlhIFE5OSBDb25maXJtZWQiKQpwMmIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICBnZ3RpdGxlKCJDYWxpZm9ybmlhIFE5OSBDb25maXJtZWQiKSArIHlsaW0oMCwxMDApKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSBDb25maXJtZWQiKQoKI1NhbiBEaWVnbyBDb3VudHkgKFExMDgxNDMpCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMTA4MTQzIikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCnAzYSA8LSB0ZXN0ICU+JQogICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICBnZ3RpdGxlKCJTYW4gRGllZ28gQ291bnR5IChRMTA4MTQzKSBDb25maXJtZWQiKQpwM2IgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICBnZ3RpdGxlKCJTYW4gRGllZ28gQ291bnR5IChRMTA4MTQzKSBDb25maXJtZWQiKSArIHlsaW0oMCwxMDApKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSBDb25maXJtZWQiKQoKI0Zsb3JpZGEgKFE4MTIpCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRODEyIikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxjb25maXJtZWRfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCnA0YSA8LSB0ZXN0ICU+JQogICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICBnZ3RpdGxlKCJGbG9yaWRhIChRODEyKSBDb25maXJtZWQiKQpwNGIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICBnZ3RpdGxlKCJGbG9yaWRhIChRODEyKSBDb25maXJtZWQiKSArIHlsaW0oMCwxMDApKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSBDb25maXJtZWQiKQoKCiNTdC4gTHVjaWUgQ291bnR5IChRNDk0NTY0KQp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTQ5NDU2NCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsY29uZmlybWVkX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQpwNWEgPC0gdGVzdCAlPiUKICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiU3QuIEx1Y2llIENvdW50eSAoUTQ5NDU2NCkgQ29uZmlybWVkIikKcDViIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiU3QuIEx1Y2llIENvdW50eSAoUTQ5NDU2NCkgQ29uZmlybWVkIikgKyB5bGltKDAsMTAwKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgQ29uZmlybWVkIikKCgpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NiAsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQojTm90IGNvdW50aW5nIHNsb3BlcyB0aGF0IHdlcmUgaW50ZXJwb2xhdGVkIG91dCBvZiBkb21haW4gZml4ZWQgY2FsaWZvcm5pYSdzIHBsb3QKKCBwMGEgKyBwMWEgKSAvICggcDBiICsgcDFiICkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYgLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KKCBwMmEgKyBwM2EgKSAvICggcDJiICsgcDNiICkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYgLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KKCBwNGEgKyBwNWEpIC8gKCBwNGIgKyBwNWIpCmBgYAoKCiMjIFBsb3QgRGVhdGggQ3VydmVzIGZvciBTZWxlY3QgTG9jYXRpb25zCgpTaG93IGhvdyBpbnRlcnBvbGF0aW9uIHdvcmtzIG9uIGRlYXRocwoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JQogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGRlYXRoc19sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTMwIikgJT4lIAogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICAlPiUKICAgICAgICBtdXRhdGUoZGF0ZV9hc251bWVyaWMgPSBkYXRlX2FzZGF0ZSAlPiUgYXMubnVtZXJpYygpICkKCnAwYSA8LSB0ZXN0ICU+JQogICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICBnZ3RpdGxlKCJVU0EgUTMwIERlYXRocyIpICMgKyBmYWNldF93cmFwKH5kYXRhc2V0KSAKCnAwYiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMyApICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIgICkgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgIGdndGl0bGUoIlVTQSBRMzAgRGVhdGhzIikgKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSBEZWF0aHMiKSAjICsgZmFjZXRfd3JhcCh+ZGF0YXNldCkKCiNwMGEgLyBwMGIKCgojIyMjIwojQ2hpbmEgUTE0OAoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxkZWF0aHNfbG9nX2dyb3VwX251bWJlcikpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMTQ4IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxkZWF0aHNfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKCnAxYSA8LSB0ZXN0ICU+JSAKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiQ2hpbmEgUTE0OCBEZWF0aHMiKQoKcDFiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiQ2hpbmEgUTE0OCBEZWF0aHMiKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgRGVhdGhzIikKICAgCgojcDFhIC8gcDFiCgojSW5kaWEKIyJRNjY4IgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlE2NjgiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGRlYXRoc19sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCgpwMmEgPC0gdGVzdCAlPiUKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiSW5kaWEgUTY2OCBEZWF0aHMiKQoKcDJiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiSW5kaWEgUTY2OCBEZWF0aHMiKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgRGVhdGhzIikKIAogIAojcDJhIC8gcDJiCgojQmV4YXIKIyJRMTY4NjEiCgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLGRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTE2ODYxIikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCxkZWF0aHNfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCBkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgoKcDNhIDwtIHRlc3QgJT4lCiAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgIGdndGl0bGUoIkJleGFyIENvdW50eSBRMTY4NjEgRGVhdGhzIikKCnAzYiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkJleGFyIENvdW50eSBRMTY4NjEgRGVhdGhzIikgKyB5bGltKDAsMTAwKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgRGVhdGhzIikKICAgCiNwM2EgLyBwM2IKCgoKI0l0YWx5CiMiUTM4IgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlEzOCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsZGVhdGhzX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9ZGVhdGhzX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKCnA0YSA8LSB0ZXN0ICU+JQpnZ3Bsb3QoKSArIAogICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJdGFseSBRMzggRGVhdGhzIikKCnA0YiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkl0YWx5IFEzOCBEZWF0aHMiKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgRGVhdGhzIikKICAgCiAgICAKI3A0YSAvIHA0YgoKCgojU291dGggS29yZWEKIyJRODg0IgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCxkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlE4ODQiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLGRlYXRoc19sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIGRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCgpwNWEgPC0gdGVzdCAlPiUKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiU291dGggS29yZWEgUTg4NCAgRGVhdGhzIikKCnA1YiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PWRlYXRoc19sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT1kZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIlNvdXRoIEtvcmVhIFE4ODQgRGVhdGhzIikgKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSBEZWF0aHMiKQogICAKICAgIAojcDVhIC8gcDViCmBgYAoKSSBuZWVkIHRvIGZpeCB0aGlzLCBVU0EgaGFzIGEgZnJhY3Rpb24gb2YgYSBkZWF0aAoKTm90ZSB0aGUgZGlzY29udGludWl0eSBpbiBDaGluIHdoZW4gdGhleSBhZGRlZCB0aG9zZSAxayBkZWF0aHMgdG8gdGhlIHRvdGFsCgpJbmRpYSBkZWF0aHMgaXMgYnJva2VuLCB3ZSBzaG91bGRuJ3QgYmUgaW50ZXJwb2xhdGluZyBhIHJhdGUgYmVmb3JlIHdlIHRoaW5rIHRoZSBudW1iZXIgaXMgZ3JlYXRlciB0aGFuIDAKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NiAsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQoocDBhICsgcDFhICsgcDJhICkgLyAocDBiICsgcDFiICsgcDJiICkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYgLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KKHAzYSArIHA0YSArIHA1YSkgLyAocDNiICsgcDRiICsgcDViKQpgYGAKCgoKIyMgUGxvdCBUZXN0aW5nIEN1cnZlcyBmb3IgU2VsZWN0IExvY2F0aW9ucwoKU2hvdyBob3cgaW50ZXJwb2xhdGlvbiB3b3JrcyBvbiB0ZXN0ZWQKClVTIGlzIGFuIGV4YW1wbGUgd2hlcmUgd2UgaW50ZXJwb2xhdGVkIHBhc3Qgb3VyIGF2YWlsYWJsZSBkYXRhLiBTaG91bGRuJ3QgZG8gdGhhdCBlaXRoZXIhCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCx0ZXN0ZWRfcGVvcGxlX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMzAiKSAlPiUgCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgICU+JQogICAgICAgIG11dGF0ZShkYXRlX2FzbnVtZXJpYyA9IGRhdGVfYXNkYXRlICU+JSBhcy5udW1lcmljKCkgKQoKcDBhIDwtIHRlc3QgJT4lCiAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgZ2d0aXRsZSgiVVNBIFEzMCBUZXN0ZWQiKSAgIysgZmFjZXRfd3JhcCh+ZGF0YXNldCkgCgpwMGIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zICkgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIgICkgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgZ2d0aXRsZSgiVVNBIFEzMCB0ZXN0ZWRfcGVvcGxlIikgKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSB0ZXN0ZWRfcGVvcGxlIikgIyArIGZhY2V0X3dyYXAofmRhdGFzZXQpCgojcDBhIC8gcDBiCgoKIyMjIyMKI0NoaW5hIFExNDgKCnRlc3QgPC0gbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsd2lraWRhdGFfaWQsdGVzdGVkX3Blb3BsZV9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlExNDgiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLHRlc3RlZF9wZW9wbGVfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKCnAxYSA8LSB0ZXN0ICU+JSAKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJDaGluYSBRMTQ4IHRlc3RlZF9wZW9wbGUiKQoKcDFiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkNoaW5hIFExNDggdGVzdGVkX3Blb3BsZSIpKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSB0ZXN0ZWRfcGVvcGxlIikKICAgCgojcDFhIC8gcDFiCgojSW5kaWEKIyJRNjY4IgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCx0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRNjY4IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCx0ZXN0ZWRfcGVvcGxlX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgoKcDJhIDwtIHRlc3QgJT4lCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiSW5kaWEgUTY2OCB0ZXN0ZWRfcGVvcGxlIikKCnAyYiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJbmRpYSBRNjY4IHRlc3RlZF9wZW9wbGUiKSsgeWxhYigiRGFpbHkgUGVyY2VudCBDaGFuZ2UgdGVzdGVkX3Blb3BsZSIpCiAKICAKI3AyYSAvIHAyYgoKI0JleGFyCiMiUTE2ODYxIgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCx0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMTY4NjEiKSAlPiUgCiAgICAgICAgbXV0YXRlKGdyb3VwPXBhc3RlKGRhdGFzZXQsIHdpa2lkYXRhX2lkLHRlc3RlZF9wZW9wbGVfbG9nX2dyb3VwX251bWJlcikpICU+JQogICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICMlPiUKICAgICAgICAjbXV0YXRlKCB0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSA9IGJyZWFrcG9pbnRzKGZvcm11bGE9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgfiAxLCBkYXRhPS4gKSAlPiUgZml0dGVkLnZhbHVlcygpICkKCgpwM2EgPC0gdGVzdCAlPiUKICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICBnZ3RpdGxlKCJCZXhhciBDb3VudHkgUTE2ODYxIHRlc3RlZF9wZW9wbGUiKQoKcDNiIDwtIHRlc3QgJT4lCiAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICAgICAgICBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0ICksIGFscGhhPTEsIGNvbG9yPSJibGFjayIpICsKICAgICAgICAgI2dlb21fc21vb3RoKCBhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UpLCBhbHBoYT0uMywgc3Bhbj0uMDUpICsgIywgc3Bhbj0uMDUKICAgICAgICAgI2dlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICAgICAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgICAgICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkJleGFyIENvdW50eSBRMTY4NjEgdGVzdGVkX3Blb3BsZSIpICsgeWxpbSgwLDEwMCkrIHlsYWIoIkRhaWx5IFBlcmNlbnQgQ2hhbmdlIHRlc3RlZF9wZW9wbGUiKQogICAKI3AzYSAvIHAzYgoKCgojSXRhbHkKIyJRMzgiCgp0ZXN0IDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LHdpa2lkYXRhX2lkLHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSkgJT4lIGZpbHRlcih3aWtpZGF0YV9pZD09IlEzOCIpICU+JSAKICAgICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCwgd2lraWRhdGFfaWQsdGVzdGVkX3Blb3BsZV9sb2dfZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgIyU+JQogICAgICAgICNtdXRhdGUoIHRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlID0gYnJlYWtwb2ludHMoZm9ybXVsYT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKQoKCnA0YSA8LSB0ZXN0ICU+JQpnZ3Bsb3QoKSArIAogICBnZW9tX3BvaW50KCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwKSkgKyAjCiAgICNnZW9tX2xpbmUoZGF0YT10ZW1wX2RmMiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXRfbWVhbiksIGNvbG9yPSJibGFjayIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgdGhlbWVfYncoKSArCiAgIGdndGl0bGUoIkl0YWx5IFEzOCB0ZXN0ZWRfcGVvcGxlIikKCnA0YiA8LSB0ZXN0ICU+JQogICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgZ2VvbV9wb2ludCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCApLCBhbHBoYT0xLCBjb2xvcj0iYmxhY2siKSArCiAgICAgICAgICNnZW9tX3Ntb290aCggYWVzKHg9ZGF0ZV9hc2RhdGUgLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlKSwgYWxwaGE9LjMsIHNwYW49LjA1KSArICMsIHNwYW49LjA1CiAgICAgICAgICNnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1kYXRhc2V0LCBncm91cD1ncm91cCkpICsgIwogICAgICAgICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICAgICAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJdGFseSBRMzggdGVzdGVkX3Blb3BsZSIpKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSB0ZXN0ZWRfcGVvcGxlIikKICAgCiAgICAKI3A0YSAvIHA0YgoKCgojU291dGggS29yZWEKIyJRODg0IgoKdGVzdCA8LSBsaHNfbG9uZ19jbGVhbl9pbXB1dGVkICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUoZGF0YXNldCx3aWtpZGF0YV9pZCx0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSkpICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRODg0IikgJT4lIAogICAgICAgIG11dGF0ZShncm91cD1wYXN0ZShkYXRhc2V0LCB3aWtpZGF0YV9pZCx0ZXN0ZWRfcGVvcGxlX2xvZ19ncm91cF9udW1iZXIpKSAlPiUKICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAjJT4lCiAgICAgICAgI211dGF0ZSggdGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UgPSBicmVha3BvaW50cyhmb3JtdWxhPXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlIH4gMSwgZGF0YT0uICkgJT4lIGZpdHRlZC52YWx1ZXMoKSApCgoKcDVhIDwtIHRlc3QgJT4lCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiU291dGggS29yZWEgUTg4NCAgdGVzdGVkX3Blb3BsZSIpCgpwNWIgPC0gdGVzdCAlPiUKICAgICAgIGdncGxvdCgpICsgCiAgICAgICAgIGdlb21fcG9pbnQoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4zKSArCiAgICAgICAgIGdlb21fbGluZShhZXMoeD1kYXRlX2FzZGF0ZSAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQgKSwgYWxwaGE9MSwgY29sb3I9ImJsYWNrIikgKwogICAgICAgICAjZ2VvbV9zbW9vdGgoIGFlcyh4PWRhdGVfYXNkYXRlICwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZSksIGFscGhhPS4zLCBzcGFuPS4wNSkgKyAjLCBzcGFuPS4wNQogICAgICAgICAjZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT10ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXApKSArICMKICAgICAgICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgICAgICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiU291dGggS29yZWEgUTg4NCB0ZXN0ZWRfcGVvcGxlIikgKyB5bGFiKCJEYWlseSBQZXJjZW50IENoYW5nZSB0ZXN0ZWRfcGVvcGxlIikKICAgCiAgICAKI3A1YSAvIHA1YgpgYGAKCgpOb3RlIHRoYXQgQ2hpbmEgY291bnRzIG9mIHRlc3RpbmcgYXJlIGFsbW9zdCBuZXZlciBnaXZlbiBhdCB0aGUgbmF0aW9uYWwgbGV2ZWwuIFdlIGhhdmUgc29tZSBicm9rZW4gZG93biBieSBzcGVjaWZpYyBwcm92aW5jZXMgYnV0IHRhYmxlcyB1c3VhbGx5IGRvbid0IGhhdmUgYSAiQ2hpbmEiIHJvdy4KCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NiAsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQoocDBhICsgcDFhICsgcDJhICkgLyAocDBiICsgcDFiICsgcDJiICkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYgLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KKHAzYSArIHA0YSArIHA1YSkgLyAocDNiICsgcDRiICsgcDViKQpgYGAKCgojIEFsaWduaW5nIEN1cnZlcyBieSBUYWtlb2ZmCgpgYGB7ciwgZWNobz1GQUxTRSx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQoKbGlicmFyeShkYXRhLnRhYmxlKQpnZW9uYW1lcyA8LSBmcmVhZCgiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvYWxsQ291bnRyaWVzLnR4dCIsIHNlcD0iXHQiKSAlPiUgbXV0YXRlX2lmKGlzLm51bWVyaWMsYXMuY2hhcmFjdGVyKSAlPiUgbXV0YXRlX2lmKGlzLmZhY3Rvcixhcy5jaGFyYWN0ZXIpCmRpbShnZW9uYW1lcykgIzEyLDAwNiw0MjYKCmdlb25hbWVzX3NtYWxsIDwtIGdlb25hbWVzICU+JSBkcGx5cjo6c2VsZWN0KGdlb25hbWVpZD1WMSwgbmFtZV90ZXh0PVYyKSAlPiUgaW5uZXJfam9pbiggbGhzX2xvbmdfY2xlYW5faW1wdXRlZCAlPiUgZHBseXI6OnNlbGVjdChnZW9uYW1laWQpICU+JSBkaXN0aW5jdCgpICkKZGltKGdlb25hbWVzX3NtYWxsKQoKZGZfc2xvcGVzIDwtIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIAogICAgICAgICAgICAgZ3JvdXBfYnkoZ2lkX2dlb25hbWVpZF93aWtpZGF0YV9pZCwgZ2lkLCBnZW9uYW1laWQsIHdpa2lkYXRhX2lkLCBkYXRlX2FzZGF0ZSkgJT4lIAogICAgICAgICAgICAgc3VtbWFyaXNlKAogICAgICAgICAgICAgICAgICAgIGNvbmZpcm1lZD1tZWRpYW4oY29uZmlybWVkLCBuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICBkZWF0aHM9bWVkaWFuKGRlYXRocywgbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgdGVzdGVkX3Blb3BsZT1tZWRpYW4odGVzdGVkX3Blb3BsZSwgbmEucm09VCksCiAgICAgICAgICAgICAgICAgICAgdGVzdGVkX3NhbXBsZXM9bWVkaWFuKHRlc3RlZF9zYW1wbGVzLCBuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX3lfaGF0PW1lZGlhbihjb25maXJtZWRfbG9nX3lfaGF0LCBuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICBkZWF0aHNfbG9nX3lfaGF0PW1lZGlhbihkZWF0aHNfbG9nX3lfaGF0LCBuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICB0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdD1tZWRpYW4odGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIG5hLnJtPVQpLAoKICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlPW1lZGlhbihjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICBkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlPW1lZGlhbihkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlLCBuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICB0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZT1tZWRpYW4odGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2UsIG5hLnJtPVQpLAoKICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0PW1lZGlhbihjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0LCBuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICBkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0PW1lZGlhbihkZWF0aHNfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0LCBuYS5ybT1UKSwKICAgICAgICAgICAgICAgICAgICB0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdD1tZWRpYW4odGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQsIG5hLnJtPVQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgI3Rlc3RlZF9zYW1wbGVzX2xvZ195X2hhdD1tZWRpYW4odGVzdGVkX3NhbXBsZXNfbG9nX3lfaGF0LCBuYS5ybT1UKSwgI2hhdmVuJ3Qgd3JpdHRlbiB0aGUgaW50ZXJwIGZvciB0aGlzIHlldAogICAgICAgICAgICAgICAgICAgICkgJT4lCiAgICAgICAgICAgICAjdW5ncm91cCgpICU+JQogICAgICAgICAgICAgbGVmdF9qb2luKGdlb25hbWVzX3NtYWxsKSAlPiUKICAgICAgICAgICAgIGdyb3VwX2J5KGdpZF9nZW9uYW1laWRfd2lraWRhdGFfaWQpICU+JSAKICAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICAgIG11dGF0ZSh0ID0gcm93X251bWJlcigpKSAlPiUKICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0X2ZkPXRzaWJibGU6OmRpZmZlcmVuY2UoY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCkpICU+JQogIAogICAgICAgICAgICAgI1NvIHRoZXJlIGFyZSBvbmVzIHRoYXQgc3RhcnQgbG93IGFuZCBidWlsZCB1cAogICAgICAgICAgICAgbXV0YXRlKHRfYWxsaWduZWRfbWF4ZmQgPSAgY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdF9mZD09bWF4KGNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXRfZmQsbmEucm09VCkgKSAlPiUgCiAgICAgICAgICAgICAjYnV0IHRoZXJlIGFyZSBvdGhlciBvbmVzIHRoYXQgZ28gZnJvbSB6ZXJvIHRvIGhpZ2ggYW5kIHRob3NlIGFyZW4ndCBnZXR0aW5nIGNhdWdodCBieSB0aGUgdG9wIGFib3ZlCiAgICAgICAgICAgICBtdXRhdGUodF9hbGxpZ25lZF9tYXhfYXRfMCA9ICBjb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0PT1tYXgoY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCxuYS5ybT1UKSAmIHQ9PTEgKSAlPiUgCgogICAgICAgICAgICAgbXV0YXRlKHRfYWxsaWduZWQgPSBpZmVsc2UodF9hbGxpZ25lZF9tYXhfYXRfMCB8ICh0X2FsbGlnbmVkX21heGZkICYgbWF4KHRfYWxsaWduZWRfbWF4X2F0XzAsIG5hLnJtPVQpPT1GKSAsIHQsIE5BKSApICU+JSAKICAgICAgICAgICAgIG11dGF0ZSh0X2FsbGlnbmVkID0gbWF4KHRfYWxsaWduZWQsIG5hLnJtPVQpICkgJT4lCiAgICAgICAgICAgICBtdXRhdGUodF9hbGxpZ25lZCA9IHQtbWF4KHRfYWxsaWduZWQsIG5hLnJtPVQpICkgJT4lCgogICAgICAgICAgICAgbXV0YXRlKHRfYWxsaWduZWRfZmlyc3Rjb25maXJtZWQgPSBpZmVsc2UoY29uZmlybWVkPT1taW4oY29uZmlybWVkLCBuYS5ybT1UKSAsIHQsIE5BKSApICU+JSAKICAgICAgICAgICAgIG11dGF0ZSh0X2FsbGlnbmVkX2ZpcnN0Y29uZmlybWVkID0gbWF4KHRfYWxsaWduZWRfZmlyc3Rjb25maXJtZWQsIG5hLnJtPVQpICkgJT4lCiAgICAgICAgICAgICBtdXRhdGUodF9hbGxpZ25lZF9maXJzdGNvbmZpcm1lZCA9IHQtbWF4KHRfYWxsaWduZWRfZmlyc3Rjb25maXJtZWQsIG5hLnJtPVQpICkgJT4lCgogICAgICAgICAgICAgI3RoaXMgdGhyb3dzIGEgYnVuY2ggb2YgaW5maW5pdGUgbWlzc2luZyBiZWNhdXNlIG9mIGNvdW50cmllcyB0aGF0IGhhdmVuJ3QgeWV0IGhpdCAxMDAKICAgICAgICAgICAgICNtdXRhdGUodF9hbGxpZ25lZF8xMDBjb25maXJtZWRfMTAwID0gaWZlbHNlKGNvbmZpcm1lZD49MTAwICAsIHQsIE5BKSApICU+JSAKICAgICAgICAgICAgICNtdXRhdGUodF9hbGxpZ25lZF8xMDBjb25maXJtZWRfMTAwID0gaWZlbHNlKHRfYWxsaWduZWRfMTAwY29uZmlybWVkXzEwMD09bWluKHRfYWxsaWduZWRfMTAwY29uZmlybWVkXzEwMCwgbmEucm09VCkgLCB0LCBOQSkgKSAlPiUgCiAgICAgICAgICAgICAjbXV0YXRlKHRfYWxsaWduZWRfMTAwY29uZmlybWVkID0gdC1tYXgodF9hbGxpZ25lZF8xMDBjb25maXJtZWRfMTAwLCBuYS5ybT1UKSApICU+JQogICAgICAgICAgICAgI2RwbHlyOjpzZWxlY3QoLXRfYWxsaWduZWRfMTAwY29uZmlybWVkXzEwMCkgJT4lCiAgICAgICAgICAgICB1bmdyb3VwKCkKYGBgCgpgYGB7ciwgZXZhbD1GfQoKbGlicmFyeShpbmZvdGhlbykKI09uY2Ugd2UgcmVtb3ZlZCB0aGUgbm8gdmFyaWFuY2UgcGxhY2VzIG15IGFsaWdubWVudCBoYXMgbW9yZSBtdXR1YWwgaW5mb3JtYXRpb24gdGhhbiBlaXRoZXIgZmlyc3QgY29uZmlybWVkIG9yIDEwMCBjb25maXJtZWQKbXV0aW5mb3JtYXRpb24oWD1kZl9zbG9wZXMgJT4lIGRwbHlyOjpzZWxlY3QodCx0X2FsbGlnbmVkLHRfYWxsaWduZWRfZmlyc3Rjb25maXJtZWQsY29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCkgJT4lIGRpc2NyZXRpemUoKSwgbWV0aG9kPSJlbXAiKSAjd2Ugb3V0cGVyZm9ybWVkIHRfYWxsaWduZWRfMTAwY29uZmlybWVkIGJ1dCBpdCB3YXNuJ3QgYXZhaWwgZm9yIG1vc3QKCiNkZl9zbG9wZXMgJT4lIGZpbHRlcihhYnModF9hbGxpZ25lZCk8MjAsYWJzKHRfYWxsaWduZWRfMTAwY29uZmlybWVkXzEwMCk8MjApICU+JSBqYW5pdG9yOjp0YWJ5bCh0X2FsbGlnbmVkLCB0X2FsbGlnbmVkXzEwMGNvbmZpcm1lZF8xMDApCiNoaXN0KGRmX3Nsb3BlcyR0X2FsbGlnbmVkIC0gZGZfc2xvcGVzJHRfYWxsaWduZWRfMTAwY29uZmlybWVkXzEwMCwgYnJlYWtzPTUwKQogIApgYGAKClBsb3Qgb2YgY3VydmVzIHJhdyBhbmQgdGhlbiBjdXJ2ZXMgYWxsaWduZWQgYnkgdGFrZW9mZiBzdGFydAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMiwgZWNobz1GQUxTRSx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQoKI2RmX3Nsb3BlcyAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKHdpa2lkYXRhX2lkKSkgJT4lCiMgICAgICAgICAgICAgIGdncGxvdCgpICsgCiMgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9dF9hbGxpZ25lZCAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCwgZ3JvdXA9d2lraWRhdGFfaWQpLCBhbHBoYT0uMDUsIGNvbG9yPSJibHVlIikgKwojICAgICAgICAgICAgICB0aGVtZV9idygpICsKIyAgICAgICAgICAgICAgZ2d0aXRsZSgiSW50ZXJwb2xhdGVkIGxvZyBjb3VudCBieSBBbGxpZ25lZCBUIikgKyB5bGltKDAsMTAwKQoKCnBfdF9hbGxpZ25lZF9maXJzdGNvbmZpcm1lZCA8LSAgZGZfc2xvcGVzICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUod2lraWRhdGFfaWQpKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD10X2FsbGlnbmVkX2ZpcnN0Y29uZmlybWVkICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0LCBncm91cD1ncm91cCwgY29sb3I9d2lraWRhdGFfaWQpLCBhbHBoYT0xKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkludGVycG9sYXRlZCBsb2cgY291bnQgYnkgVCIpICsgeWxpbSgwLDEwMCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2doaWdobGlnaHQod2lraWRhdGFfaWQgJWluJSBjKCdRMzAnLCdRMTQzOScsJ1E2NjgnLCdRODg0JywnUTE2ODYxJywnUTE1OScsJ1EzOCcpLCB1bmhpZ2hsaWdodGVkX3BhcmFtcz1saXN0KGFscGhhPS4xKSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3Ntb290aCggYWVzKHg9dF9hbGxpZ25lZF9maXJzdGNvbmZpcm1lZCAsIHk9Y29uZmlybWVkX2xvZ195X2hhdF9wZXJjZW50X2NoYW5nZV95X2hhdCksIHNwYW4gPSAwLjA1KSAgKyB4bGltKC01MCwxMDApCgojcF90X2FsbGlnbmVkX2ZpcnN0Y29uZmlybWVkCgoKcF90X2FsbGlnbmVkIDwtIGRmX3Nsb3BlcyAlPiUgbXV0YXRlKGdyb3VwPXBhc3RlKHdpa2lkYXRhX2lkKSkgJT4lIAogICAgICAgICAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PXRfYWxsaWduZWQgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQsIGdyb3VwPWdyb3VwLCBjb2xvcj13aWtpZGF0YV9pZCksIGFscGhhPTEpICsKICAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgIGdndGl0bGUoIkludGVycG9sYXRlZCBsb2cgY291bnQgYnkgQWxsaWduZWQgVCIpICsgeWxpbSgwLDEwMCkgKwogICAgICAgICAgICAgICBnZ2hpZ2hsaWdodCh3aWtpZGF0YV9pZCAlaW4lIGMoJ1EzMCcsJ1ExNDM5JywnUTY2OCcsJ1E4ODQnLCdRMTY4NjEnLCdRMTU5JywnUTM4JyksIHVuaGlnaGxpZ2h0ZWRfcGFyYW1zPWxpc3QoYWxwaGE9LjEpKSArCiAgICAgICAgICAgICAgIGdlb21fc21vb3RoKCBhZXMoeD10X2FsbGlnbmVkICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0KSwgc3BhbiA9IDAuMDUpICsgeGxpbSgtNTAsMTAwKQoKI3BfdF9hbGxpZ25lZAojZGZfc2xvcGVzICU+JSBtdXRhdGUoZ3JvdXA9cGFzdGUod2lraWRhdGFfaWQpKSAlPiUgCiNnZ3Bsb3QoKSArIAojICAgZ2VvbV9saW5lKCBhZXMoeD10X2FsbGlnbmVkICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0LCBncm91cD1ncm91cCwgY29sb3I9d2lraWRhdGFfaWQpLCBhbHBoYT0xKSArCiMgICB0aGVtZV9idygpICsKIyAgIGdndGl0bGUoIkludGVycG9sYXRlZCBsb2cgY291bnQgYnkgQWxsaWduZWQgVCIpICsgeWxpbSgwLDEwMCkgICsgeGxpbSgwLDEwMCkgKwojICAgZ2doaWdobGlnaHQod2lraWRhdGFfaWQgJWluJSBjKCdRMzAnLCdRMTQzOScsJ1E2NjgnLCdRODg0JywnUTE2ODYxJywnUTE1OScsJ1EzOCcpLCB1bmhpZ2hsaWdodGVkX3BhcmFtcz1saXN0KGFscGhhPS4xKSkgKwojICAgZ2VvbV9zbW9vdGgoIGFlcyh4PXRfYWxsaWduZWQgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQpLCBzcGFuID0gMC4wNSkgCgoKCmBgYAoKVGhlIGlkZWEgaGVyZSBpcyB0aGF0IGNvbXBsZXRlbHkgdW5jb25zdHJhaW5lZCwgQ09WSUQtMTkgZ3Jvd3RoIHNob3VsZCBmb2xsb3cgYSBsb2dpc3RpYyBjdXJ2ZSwgZmxhdCwgdXBzd2luZywgY29uc3RhbnQgZ3Jvd3RoLCBkb3duc3dpbmcsIGFuZCBmbGF0IGFnYWluLiBUaGUgYXNzdW1wdGlvbiBvZiBubyB1bmNvbnN0cmFpbmVkIGdyb3d0aCBubyBsb25nZXIgaG9sZHMgYmVjYXVzZSB0aGUgd29ybGQgaXMgcmVhY3RpbmcsIGJ1dCB0aGVyZSdzIHN0aWxsIGEgcHJldHR5IHVuaWZvcm1seSBjaGFyYWN0ZXJpc3RpYyB1cHN3aW5nIGFjcm9zcyBnZW9ncmFwaGljIHVuaXRzLiBXZSBsb29rIGZvciB0aGlzIHNpZ25hbCBvZiB0aGUgbGFyZ2VzdCBmaXJzdCBkaWZmZXJlbmNlIGluIHRoZSBkYWlseSBwZXJjZW50IGNoYW5nZSwgY2FsbCB0aGF0IHRoZSB0YWtlb2ZmIGRhdGUsIGFuZCB0aGVuIGFsbGlnbiBhbGwgdGhlIHRpbWUgc2VyaWVzIHdpdGggdGhhdCBkYXRlIGFzIDAuCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KcF90X2FsbGlnbmVkX2ZpcnN0Y29uZmlybWVkICAvIHBfdF9hbGxpZ25lZCAKYGBgCgoKCgojIyBQbG90cyBieSBDb3VudHJpZXMKCldlIGhhdmUgdG8gYWRkIGdlb2NvZGVzIHRvIHRoZSBtYXAgcGxhY2VtZW50cwoKYGBge3J9CmFkbWluMCA8LSByZWFkUkRTKCIvbWVkaWEvc2t5bmV0Mi85MDU4ODRmMC03NTQ2LTQyNzMtOTA2MS0xMmE3OTA4MzBiZWIvcndkX2dpdGh1Yl9wcml2YXRlL05FU1Njb3ZpZDE5L2RhdGFfaW4vYWRtaW4wLlJkcyIpCmFkbWluMSA8LSByZWFkUkRTKCIvbWVkaWEvc2t5bmV0Mi85MDU4ODRmMC03NTQ2LTQyNzMtOTA2MS0xMmE3OTA4MzBiZWIvcndkX2dpdGh1Yl9wcml2YXRlL05FU1Njb3ZpZDE5L2RhdGFfaW4vYWRtaW4xLlJkcyIpCmFkbWluMiA8LSByZWFkUkRTKCIvbWVkaWEvc2t5bmV0Mi85MDU4ODRmMC03NTQ2LTQyNzMtOTA2MS0xMmE3OTA4MzBiZWIvcndkX2dpdGh1Yl9wcml2YXRlL05FU1Njb3ZpZDE5L2RhdGFfaW4vYWRtaW4yLlJkcyIpCgpyZXhfY2xlYW4gPC0gZnVuY3Rpb24oeCl7IHggJT4lIHN0cmluZ2k6OnN0cmlfdHJhbnNfZ2VuZXJhbCgibGF0aW4tYXNjaWkiKSAlPiUgc3RyaW5naTo6c3RyaV9yZXBsYWNlX2FsbChyZWdleD0iW15BLVphLXowLTldIiwiIikgJT4lIHRvbG93ZXIoKSB9ICNzbyBpbmRpdmlkdWFsbHksIGVhY2ggc3RyaW5nIHNob3VsZCBiZSBkZXZvaWQgb2Ygc3BhY2VzLG5vbmNoYXJhY3RlcnMsIGFuZCBub25sYXRpbgoKcmV4X2FkbWluX2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKHgpIHsKICB4ICU+JSAKICBsZWZ0X2pvaW4oYWRtaW4wICkgJT4lCiAgbGVmdF9qb2luKGFkbWluMSApICAlPiUKICBsZWZ0X2pvaW4oYWRtaW4yICkgJT4lCiAgbXV0YXRlKGdpZD1pZmVsc2UoIWlzLm5hKGFkbWluMl9uYW1lX2NsZWFuKSAmIGFkbWluMl9uYW1lX2NsZWFuIT0nJyxnaWQyLGlmZWxzZSghaXMubmEoYWRtaW4xX25hbWVfY2xlYW4pICYgYWRtaW4xX25hbWVfY2xlYW4hPScnLCBnaWQxLCBnaWQwKSkpICU+JQogIG11dGF0ZSh3aWtpZGF0YV9pZD1pZmVsc2UoIWlzLm5hKGFkbWluMl9uYW1lX2NsZWFuKSAmIGFkbWluMl9uYW1lX2NsZWFuIT0nJyx3aWtpZGF0YV9pZDIsaWZlbHNlKCFpcy5uYShhZG1pbjFfbmFtZV9jbGVhbikgJiBhZG1pbjFfbmFtZV9jbGVhbiE9JycsIHdpa2lkYXRhX2lkMSwgd2lraWRhdGFfaWQwKSkpICU+JQogIG11dGF0ZShnZW9uYW1laWQ9aWZlbHNlKCFpcy5uYShhZG1pbjJfbmFtZV9jbGVhbikgJiBhZG1pbjJfbmFtZV9jbGVhbiE9JycsZ2VvbmFtZWlkMixpZmVsc2UoIWlzLm5hKGFkbWluMV9uYW1lX2NsZWFuKSAmIGFkbWluMV9uYW1lX2NsZWFuIT0nJywgZ2VvbmFtZWlkMSwgZ2VvbmFtZWlkMCkpKSAlPiUKICBtdXRhdGUoYWRtaW5fbGV2ZWw9aWZlbHNlKCFpcy5uYShhZG1pbjJfbmFtZV9jbGVhbikgJiBhZG1pbjJfbmFtZV9jbGVhbiE9JycsMixpZmVsc2UoIWlzLm5hKGFkbWluMV9uYW1lX2NsZWFuKSAmIGFkbWluMV9uYW1lX2NsZWFuIT0nJywgMSwgMCkpKQp9CgpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KaW5zdGFsbC5wYWNrYWdlcygiZ2VvZmFjZXQiKQojIG9yIGZyb20gZ2l0aHViOgojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiaGFmZW4vZ2VvZmFjZXQiKQpsaWJyYXJ5KGdlb2ZhY2V0KQpoZWFkKHVzX3N0YXRlX2dyaWQyKQoKYGBgCgojIyMgQ29uZmlybWVkLCBEZWF0aHMsIFRlc3RzCgpCeSBjb3VudHJ5IAoKYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQoKZ2FkbTM2ID0gc3RfcmVhZCgiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTZ2FkbS9kYXRhX2luL2dhZG0zNl9ncGtnL2dhZG0zNi5ncGtnIikKZ2FkbTM2X2RmIDwtIGdhZG0zNiAlPiUgYXMuZGF0YS5mcmFtZSgpCmNvdW50cmllcyA8LSBnYWRtMzZfZGYgJT4lIGRwbHlyOjpzZWxlY3QoZ2lkPUdJRF8wLCBuYW1lPU5BTUVfMCApICU+JSBkaXN0aW5jdCgpCgp0ZW1wMSA8LSBkZl9zbG9wZXMgJT4lCiAgICAgICAgICBmaWx0ZXIoIWdpZCAlPiUgc3RyX2RldGVjdCgiXyIpICkgJT4lCiAgICAgICAgICBsZWZ0X2pvaW4oY291bnRyaWVzICU+JSBkcGx5cjo6c2VsZWN0KGdpZCwgbmFtZV90ZXh0PW5hbWUpICkgJT4lIAogICAgICAgICAgI2xlZnRfam9pbihnZW9uYW1lc19zbWFsbCAgKSAlPiUgCiAgCiAgICAgICAgICBtdXRhdGUobmFtZV90ZXh0PW5hbWVfdGV4dCAlPiUgYXMuZmFjdG9yKCkpICU+JQogICAgICAgICAgbGVmdF9qb2luKHdvcmxkX2NvdW50cmllc19ncmlkMSwgYnk9YygnZ2lkJz0nY29kZV9hbHBoYTMnKSkgJT4lCiAgICAgICAgICBmaWx0ZXIoIWlzLm5hKG5hbWUpKQp0ZW1wMiA8LSB0ZW1wMSAlPiUgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lIGZpbHRlcighZHVwbGljYXRlZChnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKSkgJT4lIG11dGF0ZShuYW1lX3RleHQ9bmFtZSAlPiUgYXMuZmFjdG9yKCkpCgpoZWFkKHdvcmxkX2NvdW50cmllc19ncmlkMSkKd29ybGRfY291bnRyaWVzX2dyaWQxX3JleCA8LSB3b3JsZF9jb3VudHJpZXNfZ3JpZDEgJT4lIGZpbHRlcihuYW1lICVpbiUgdGVtcDIkbmFtZSkKZGltKHdvcmxkX2NvdW50cmllc19ncmlkMV9yZXgpCmdyaWRfcHJldmlldyh3b3JsZF9jb3VudHJpZXNfZ3JpZDFfcmV4KQoKcF9jb25maXJtZWRfZGVhdGhzX3Rlc3RfYnlfY291bnRyeSA8LSB0ZW1wMSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQpLCBjb2xvcj0icmVkIikgKyAjICN0IGFsaWduZWQgaXMgYnJva2VuIGZvciB0aGUgVS5TLiBhbmQgc29tZSBjb3VudHJpZXMsIGFsbCBpbmZpbml0ZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWRlYXRoc19sb2dfeV9oYXQpLCBjb2xvcj0iYmxhY2siKSArICMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0KSwgY29sb3I9ImJsdWUiKSArICMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJHbG9iYWwgQ292aWQtMTk6IExvZyBUZXN0ZWQgKGJsdWUpIENvbmZpcm1lZCAocmVkKSwgRGVhdGggKGJsYWNrKSIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyggY29sb3IgPSBGQUxTRSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZXRfd3JhcCh+bmFtZV90ZXh0ICAgKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fdGV4dChkYXRhPXRlbXAyLHg9MTgyODIrMjAseT0xNCxhZXMobGFiZWw9bmFtZV90ZXh0KSwgc2l6ZT0yLjUpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNvdW50cyAobG9nKSIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIkRheXMgYmVmb3JlL1NpbmNlIFRha2VvZmYgaW4gQ29uZmlybWVkIE51bWJlcnMiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNldF9nZW8ofm5hbWUsIGdyaWQgPXdvcmxkX2NvdW50cmllc19ncmlkMV9yZXgpIApgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTJ9CnBfY29uZmlybWVkX2RlYXRoc190ZXN0X2J5X2NvdW50cnkKYGBgCgpVLlMuIGJ5IFN0YXRlCgpgYGB7ciwgZmlnLndpZHRoPTE2LCBmaWcuaGVpZ2h0PTEyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9Cgp0ZW1wMSA8LSBkZl9zbG9wZXMgJT4lCiAgICAgICAgICBmaWx0ZXIoZ2lkICU+JSBzdHJfZGV0ZWN0KCJVU0FcXC5bMC05XXsxLDJ9XzEkIikgKSAlPiUKICAgICAgICAgIGxlZnRfam9pbihnZW9uYW1lc19zbWFsbCAgKSAlPiUgbXV0YXRlKG5hbWVfdGV4dD0gbmFtZV90ZXh0ICU+JSBhcy5mYWN0b3IoKSkgJT4lCiAgICAgICAgICBsZWZ0X2pvaW4odXNfc3RhdGVfZ3JpZDIsIGJ5PWMoJ25hbWVfdGV4dCc9J25hbWUnKSkgJT4lIAogICAgICAgICAgZmlsdGVyKCFpcy5uYShuYW1lX3RleHQpKQp0ZW1wMiA8LSB0ZW1wMSAlPiUgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lIGZpbHRlcighZHVwbGljYXRlZChnaWRfZ2VvbmFtZWlkX3dpa2lkYXRhX2lkKSkgJT4lIG11dGF0ZShuYW1lX3RleHQ9bmFtZV90ZXh0ICU+JSBhcy5mYWN0b3IoKSkKCiN0X2FsbGlnbmVkCnBfY29uZmlybWVkX2RlYXRoc190ZXN0X2J5X3N0YXRlX3VzIDwtIHRlbXAxICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNmaWx0ZXIoZ2lkPT0iVVNBIikgJT4lICNqdXN0IGEgdGVzdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCksIGNvbG9yPSJyZWQiKSArICMgI3QgYWxpZ25lZCBpcyBicm9rZW4gZm9yIHRoZSBVLlMuIGFuZCBzb21lIGNvdW50cmllcywgYWxsIGluZmluaXRlcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1kZWF0aHNfbG9nX3lfaGF0KSwgY29sb3I9ImJsYWNrIikgKyAjCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0KSwgY29sb3I9ImJsdWUiKSArICMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2d0aXRsZSgiQ292aWQtMTkgQnkgVS5TLiBTdGF0ZTogTG9nIFRlc3RlZCAoYmx1ZSkgQ29uZmlybWVkIChyZWQpLCBEZWF0aCAoYmxhY2spIikgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICwgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV90ZXh0KGRhdGE9dGVtcDIseD0xODI4MisyMCx5PTEyLGFlcyhsYWJlbD1uYW1lX3RleHQpLCBzaXplPTQpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ291bnRzIChsb2cpIikgKyB4bGFiKCJEYXRlIikgKyAjIkRheXMgYmVmb3JlL1NpbmNlIFRha2VvZmYgaW4gQ29uZmlybWVkIE51bWJlcnMiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyggY29sb3IgPSBGQUxTRSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNldF9nZW8ofmNvZGUpIAoKIApgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTJ9CnBfY29uZmlybWVkX2RlYXRoc190ZXN0X2J5X3N0YXRlX3VzCmBgYAoKSW5kaWEgYnkgU3RhdGUKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTIsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KCmhlYWQoaW5kaWFfZ3JpZDIpCgppbmRpYV9ncmlkMl9yZXggPC0gaW5kaWFfZ3JpZDIgJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGFkbWluMF9uYW1lX29yaWdpbmFsPSJJbmRpYSIpICU+JQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShhZG1pbjFfbmFtZV9vcmlnaW5hbD1uYW1lKSAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWRtaW4yX25hbWVfb3JpZ2luYWw9JycpICAlPiUKICAgIAogICAgICAgICAgICAgICAgICAgIG11dGF0ZShhZG1pbjBfbmFtZV9jbGVhbj1hZG1pbjBfbmFtZV9vcmlnaW5hbCAlPiUgcmV4X2NsZWFuKCkpICU+JQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShhZG1pbjFfbmFtZV9jbGVhbj1hZG1pbjFfbmFtZV9vcmlnaW5hbCAlPiUgcmV4X2NsZWFuKCkpICU+JQogICAgICAgICAgICAgICAgICAgIG11dGF0ZShhZG1pbjJfbmFtZV9jbGVhbj1hZG1pbjJfbmFtZV9vcmlnaW5hbCAlPiUgcmV4X2NsZWFuKCkpICU+JQogICAgICAgICAgICAgICAgICAgIHJleF9hZG1pbl9mdW5jdGlvbigpCgp0ZW1wMSA8LSBkZl9zbG9wZXMgJT4lCiAgICAgICAgICBmaWx0ZXIoZ2lkICU+JSBzdHJfZGV0ZWN0KCJJTkRcXC5bMC05XXsxLDJ9XzEkIikgKSAlPiUKICAgICAgICAgIGxlZnRfam9pbihpbmRpYV9ncmlkMl9yZXggICkgJT4lIAogICAgICAgICAgbXV0YXRlKG5hbWVfdGV4dD0gYWRtaW4xX25hbWVfb3JpZ2luYWwgJT4lIGFzLmZhY3RvcigpKSAlPiUgI3NldCBpdCB0byB0aGUgc3RhdGUncyBuYW1lCiAgICAgICAgICBmaWx0ZXIoIWlzLm5hKG5hbWVfdGV4dCkpCnRlbXAyIDwtIHRlbXAxICU+JSBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgZmlsdGVyKCFkdXBsaWNhdGVkKGdpZF9nZW9uYW1laWRfd2lraWRhdGFfaWQpKSAlPiUgbXV0YXRlKG5hbWVfdGV4dD1uYW1lX3RleHQgJT4lIGFzLmZhY3RvcigpKQoKI3RfYWxsaWduZWQKcF9jb25maXJtZWRfZGVhdGhzX3Rlc3RfYnlfc3RhdGVfaW5kaWEgPC0gdGVtcDEgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjZmlsdGVyKGdpZD09IlVTQSIpICU+JSAjanVzdCBhIHRlc3QKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90KCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nX3lfaGF0KSwgY29sb3I9InJlZCIpICsgIyAjdCBhbGlnbmVkIGlzIGJyb2tlbiBmb3IgdGhlIFUuUy4gYW5kIHNvbWUgY291bnRyaWVzLCBhbGwgaW5maW5pdGVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9ZGVhdGhzX2xvZ195X2hhdCksIGNvbG9yPSJibGFjayIpICsgIwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0KSwgY29sb3I9ImJsdWUiKSArICMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdndGl0bGUoIkNvdmlkLTE5IEJ5IFUuUy4gU3RhdGU6IExvZyBUZXN0ZWQgKGJsdWUpIENvbmZpcm1lZCAocmVkKSwgRGVhdGggKGJsYWNrKSIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3RleHQoZGF0YT10ZW1wMix4PTE4MjgyKzUwLHk9Ny41LGFlcyhsYWJlbD1uYW1lX3RleHQpLCBzaXplPTIuNSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNvdW50cyAobG9nKSIpICsgeGxhYigiRGF0ZSIpICsgIyJEYXlzIGJlZm9yZS9TaW5jZSBUYWtlb2ZmIGluIENvbmZpcm1lZCBOdW1iZXJzIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd1aWRlcyggY29sb3IgPSBGQUxTRSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNFcnJvcjogT3RoZXIgdGhhbiAncm93JyBhbmQgJ2NvbCcsIHZhcmlhYmxlIG5hbWVzIG9mIGEgY3VzdG9tIGdyaWQgbXVzdCBiZWdpbiB3aXRoICdjb2RlJyBvciAnbmFtZScKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNldF9nZW8ofmNvZGUsIGdyaWQgPSBpbmRpYV9ncmlkMiApICAjX3JleCAlPiUgZmlsdGVyKGNvZGUsIHJvdywgY29sLCBuYW1lKQoKIApgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTYsIGZpZy5oZWlnaHQ9MTJ9CnBfY29uZmlybWVkX2RlYXRoc190ZXN0X2J5X3N0YXRlX2luZGlhCmBgYAoKCgoKCgpUb21vcnJvdyBtb3JuaW5nIEkgdGhpbmsgbXkgam9iIGlzIHRvIGZpcnN0IGRpZmZlcmVuY2UgYWxsIG9mIHRoZXNlLiBIb3cgbWFueSB0ZXN0cywgaG93IG1hbnkgY29uZmlybWVkLCBob3cgbWFueSBkZWFkIGVhY2ggZGF5LiBGaW5kIHRoZSBsYWdzIGFuZCBsZWFkcyB3aXRoIHRoZSBoaWdoZXN0IGNvcnJlbGF0aW9uIGJldHdlZW4gdGhvc2UgdGhyZWUsIHBvc3NpYmx5IHZhcnlpbmcgYnkgY291bnRyeS4KCgoKCgoKCldoYXQgdGhpcyBnaXZlcyB1cyBpcyBhIG5pY2Ugbm9ybWFsaXplZCBkYXRhc2V0IHdoZXJlIHRoZSB0YXNrIGlzIHRvIHByZWRpY3QgdGhlIHNoYXBlIG9mIHRoYXQgZGlzdHJpYnV0aW9uLiBXZSBjb3VsZCB0cnkgdG8gcHJlZGljdCB0aW1lIHVudGlsIHRoZSB0YWtlb2ZmLCB0aGUgaW50ZW5zaXR5IG9mIHRoZSBncm93dGggYXQgdGhlIHRha2VvZmYgcG9pbnQsIHRoZSB0aW1lIHVudGlsIGl0IHJldHVybnMgdG8gemVybywgdGhlIGFyZWEgdW5kZXIgdGhlIGN1cnZlLCBvciBldmVyeSBub29rIGFuZCBjaGFuZ2UuCgoKSG93IGRvZXMgdGVzdGluZyB2YXJ5IG92ZXIgdGhpcz8KCgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyLCBlY2hvPUZBTFNFLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgcmVzdWx0cz0naGlkZSd9CgpwX3RfYWxsaWduZWRfdGVzdGVkX3Blb3BsZSA8LSBkZl9zbG9wZXMgJT4lIG11dGF0ZShncm91cD1wYXN0ZSh3aWtpZGF0YV9pZCkpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZSggYWVzKHg9dF9hbGxpZ25lZCAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXRfcGVyY2VudF9jaGFuZ2VfeV9oYXQsIGdyb3VwPWdyb3VwLCBjb2xvcj13aWtpZGF0YV9pZCksIGFscGhhPTEpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RpdGxlKCJQZXJjZW50IERheSBvbiBEYXkgSW5jcmVhc2UgaW4gVGVzdGluZyBieSBBbGxpZ25lZCBUIikgKyB5bGltKDAsMTAwKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2doaWdobGlnaHQod2lraWRhdGFfaWQgJWluJSBjKCdRMzAnLCdRMTQzOScsJ1E2NjgnLCdRODg0JywnUTE2ODYxJywnUTE1OScsJ1EzOCcpLCB1bmhpZ2hsaWdodGVkX3BhcmFtcz1saXN0KGFscGhhPS41KSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fc21vb3RoKCBhZXMoeD10X2FsbGlnbmVkICwgeT1jb25maXJtZWRfbG9nX3lfaGF0X3BlcmNlbnRfY2hhbmdlX3lfaGF0KSwgc3BhbiA9IDAuMDUpICsgeGxpbSgtNTAsMTAwKSAKCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0V9CnBfdF9hbGxpZ25lZF90ZXN0ZWRfcGVvcGxlCmBgYAoKClBsb3Qgc29tZSBzcGVjaWZpYyBjb3VudHJpZXMKCgpgYGB7cn0KCmRmX3Nsb3BlcyAlPiUgZmlsdGVyKCFpcy5uYSh0ZXN0ZWRfcGVvcGxlKSkgJT4lIGNvdW50KHdpa2lkYXRhX2lkKSAjMjkyIHBsYWNlcyB3aXRoIHRlc3RpbmcgaW5mb3JtYXRpb24KCmRmX3Nsb3BlcyAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTMwIikgJT4lIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZCkpICsgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGUpKQoKZGZfc2xvcGVzICU+JSBmaWx0ZXIod2lraWRhdGFfaWQ9PSJRMzAiKSAlPiUgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9Y29uZmlybWVkX2xvZ195X2hhdCkpICsgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0KSkKCmRmX3Nsb3BlcyAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTMwIikgJT4lIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZC90ZXN0ZWRfcGVvcGxlKSkgCgoKZGZfc2xvcGVzICU+JSBtdXRhdGUoY29uZmlybWVkX292ZXJfdGVzdGVkX3Blb3BsZT1jb25maXJtZWQvdGVzdGVkX3Blb3BsZSkgJT4lIHB1bGwoY29uZmlybWVkX292ZXJfdGVzdGVkX3Blb3BsZSkgJT4lIHN1bW1hcnkoKQpkZl9zbG9wZXMgJT4lIG11dGF0ZShjb25maXJtZWRfb3Zlcl90ZXN0ZWRfcGVvcGxlPWNvbmZpcm1lZC90ZXN0ZWRfcGVvcGxlKSAlPiUgcHVsbChjb25maXJtZWRfb3Zlcl90ZXN0ZWRfcGVvcGxlKSAlPiUgcXVhbnRpbGUocHJvYnMgPSBzZXEoMCwgMSwgMC4xKSwgbmEucm09VCkgIzkwdGggcGVyY2VudGlhbCBpcyAsMjMKCmRmX3Nsb3BlcyAlPiUgZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKHg9dF9hbGxpZ25lZCwgeT1jb25maXJtZWQvdGVzdGVkX3Blb3BsZSwgY29sb3I9d2lraWRhdGFfaWQpLCBhbHBoYT0uMikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ2hpZ2hsaWdodCh3aWtpZGF0YV9pZCAlaW4lIGMoJ1EzMCcsJ1ExNDM5JywnUTY2OCcsJ1E4ODQnLCdRMTY4NjEnLCdRMTU5JywnUTM4JyksIHVuaGlnaGxpZ2h0ZWRfcGFyYW1zPWxpc3QoYWxwaGE9LjUpKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9zbW9vdGgoIGFlcyh4PXRfYWxsaWduZWQgLCB5PWNvbmZpcm1lZC90ZXN0ZWRfcGVvcGxlKSwgc3BhbiA9IDAuMDUpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxpbSgtNSwxMDApICsgeWxpbSgwLC4yNSkgKyB0aGVtZV9idygpICN0aGVyZSBhcmUgc29tZSBvdXRsaWFycyBub3J0aCBvZiAxMAoKCm9wdGlvbnMoZ2doaWdobGlnaHRfbWF4X2xhYmVscyA9IDYwKQpkZXRhY2goZ2doaWdobGlnaHQpCmxpYnJhcnkoZ2doaWdobGlnaHQpCmxpYnJhcnkoZGF0YS50YWJsZSkKZ2VvbmFtZXMgPC0gZnJlYWQoIi9tZWRpYS9za3luZXQyLzkwNTg4NGYwLTc1NDYtNDI3My05MDYxLTEyYTc5MDgzMGJlYi9yd2RfZ2l0aHViX3ByaXZhdGUvTkVTU2NvdmlkMTkvZGF0YV90ZW1wL2FsbENvdW50cmllcy50eHQiLCBzZXA9Ilx0IikgJT4lIG11dGF0ZV9pZihpcy5udW1lcmljLGFzLmNoYXJhY3RlcikgJT4lIG11dGF0ZV9pZihpcy5mYWN0b3IsYXMuY2hhcmFjdGVyKQpkaW0oZ2VvbmFtZXMpICMxMiwwMDYsNDI2CgpnZW9uYW1lc19zbWFsbCA8LSBnZW9uYW1lcyAlPiUgZHBseXI6OnNlbGVjdChnZW9uYW1laWQ9VjEsIG5hbWVfdGV4dD1WMikgJT4lIGlubmVyX2pvaW4oIGxoc19sb25nX2NsZWFuX2ltcHV0ZWQgJT4lIGRwbHlyOjpzZWxlY3QoZ2VvbmFtZWlkKSAlPiUgZGlzdGluY3QoKSApCmRpbShnZW9uYW1lc19zbWFsbCkKCgpkZl9zbG9wZXMgJT4lIGxlZnRfam9pbihnZW9uYW1lc19zbWFsbCAgKSAlPiUgbXV0YXRlKG5hbWVfdGV4dCAlPiUgYXMuZmFjdG9yKCkpICU+JSBmaWx0ZXIoZ2lkICU+JSBzdHJfZGV0ZWN0KCJVU0FcXC5bMC05XXsxLDJ9XzEkIikpICU+JQogICAgICAgICAgIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4PXRfYWxsaWduZWQsIHk9Y29uZmlybWVkX2xvZ195X2hhdCwgY29sb3I9bmFtZV90ZXh0KSwgYWxwaGE9LjIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2doaWdobGlnaHQobWF4X2hpZ2hsaWdodCA9IDEwMEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2lkICU+JSBzdHJfZGV0ZWN0KCJVU0EiKSwgdW5oaWdobGlnaHRlZF9wYXJhbXM9bGlzdChhbHBoYT0uMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlX2RpcmVjdF9sYWJlbD1UKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9zbW9vdGgoIGFlcyh4PXRfYWxsaWduZWQgLCB5PWNvbmZpcm1lZF9sb2dfeV9oYXQsIHNwYW4gPSAwLjA1KSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGltKC01LDEwMCkgKyAjeWxpbSgwLC4yNSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICN0aGVyZSBhcmUgc29tZSBvdXRsaWFycyBub3J0aCBvZiAxMAoKZGZfc2xvcGVzICU+JSBsZWZ0X2pvaW4oZ2VvbmFtZXNfc21hbGwgICkgJT4lIG11dGF0ZShuYW1lX3RleHQgJT4lIGFzLmZhY3RvcigpKSAlPiUgZmlsdGVyKGdpZCAlPiUgc3RyX2RldGVjdCgiVVNBXFwuWzAtOV17MSwyfV8xJCIpKSAlPiUKICAgICAgICAgICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD10X2FsbGlnbmVkLCB5PXRlc3RlZF9wZW9wbGVfbG9nX3lfaGF0LCBjb2xvcj1uYW1lX3RleHQpLCBhbHBoYT0uMikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ2hpZ2hsaWdodChtYXhfaGlnaGxpZ2h0ID0gMTAwTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnaWQgJT4lIHN0cl9kZXRlY3QoIlVTQSIpLCB1bmhpZ2hsaWdodGVkX3BhcmFtcz1saXN0KGFscGhhPS4xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VfZGlyZWN0X2xhYmVsPVQpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3Ntb290aCggYWVzKHg9dF9hbGxpZ25lZCAsIHk9dGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQsIHNwYW4gPSAwLjA1KSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGltKC01LDE1MCkgKyAjeWxpbSgwLC4yNSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICN0aGVyZSBhcmUgc29tZSBvdXRsaWFycyBub3J0aCBvZiAxMAoKZGZfc2xvcGVzICU+JSBsZWZ0X2pvaW4oZ2VvbmFtZXNfc21hbGwgICkgJT4lIG11dGF0ZShuYW1lX3RleHQgJT4lIGFzLmZhY3RvcigpKSAlPiUKICAgICAgICAgICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeD10X2FsbGlnbmVkLCB5PWV4cChjb25maXJtZWRfbG9nX3lfaGF0KS9leHAodGVzdGVkX3Blb3BsZV9sb2dfeV9oYXQpLCBjb2xvcj1uYW1lX3RleHQpLCBhbHBoYT0uMikgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ2hpZ2hsaWdodChtYXhfaGlnaGxpZ2h0ID0gMTAwTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnaWQgJT4lIHN0cl9kZXRlY3QoIlVTQSIpLCB1bmhpZ2hsaWdodGVkX3BhcmFtcz1saXN0KGFscGhhPS4xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VfZGlyZWN0X2xhYmVsPVQpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3Ntb290aCggYWVzKHg9dF9hbGxpZ25lZCAsIHk9ZXhwKGNvbmZpcm1lZF9sb2dfeV9oYXQpL2V4cCh0ZXN0ZWRfcGVvcGxlX2xvZ195X2hhdCksIHNwYW4gPSAwLjA1KSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGltKC01LDEwMCkgKyB5bGltKDAsLjI1KSArIHRoZW1lX2J3KCkgI3RoZXJlIGFyZSBzb21lIG91dGxpYXJzIG5vcnRoIG9mIDEwCgojd2UgbWlnaHQgbmVlZCB0byBzd2l0Y2ggdGhpcyB0byBmZC4gQmVjYXVzZSBpdCdzIHRoZSBwZXJjZW50IG9mIHRoZSBuZXcgdGVzdHMgY29taW5nIGJhY2sgcG9zaXRpdmUgbm90IHRoZSBvbGQgb25lcy4KCiNSZW1pbmQgb3Vyc2VsdmVzIGludGVycHJldGF0aW9ucyB3aGVuIHdlIGxocwojaHR0cHM6Ly9kYXRhLmxpYnJhcnkudmlyZ2luaWEuZWR1L2ludGVycHJldGluZy1sb2ctdHJhbnNmb3JtYXRpb25zLWluLWEtbGluZWFyLW1vZGVsLwoKYGBgCgoKCgoKYGBge3IsIGV2YWw9Rn0KCmxtMSA8LSBsbShkZWF0aHMgfiAgY29uZmlybWVkLGRhdGE9bGhzX2xvbmdfbWVkaWFuICU+JSBmaWx0ZXIoQ0ZSPDEpKQpsbTIgPC0gbG0oZGVhdGhzIH4gdGVzdGVkX3Blb3BsZSArIGNvbmZpcm1lZCxkYXRhPWxoc19sb25nX21lZGlhbiAlPiUgZmlsdGVyKENGUjwxKSkKCmxpYnJhcnkoZ2dSYW5kb21Gb3Jlc3RzKTsgI2luc3RhbGwucGFja2FnZXMoJ2dnUmFuZG9tRm9yZXN0cycpCnJmMSA8LSByZnNyYyhkZWF0aHN+IGNvbmZpcm1lZCwKICAgICAgICAgICAgICAgICAgICAgIGRhdGE9bGhzX2xvbmdfbWVkaWFuICU+JSBmaWx0ZXIoQ0ZSPDEpICU+JSBhcy5kYXRhLmZyYW1lKCkgKQpnZ19lIDwtIGdnX2Vycm9yKHJmMSkKZ2dfdiA8LSBnZ192YXJpYWJsZShyZjEpCnBsb3QoZ2dfdiwgcGFuZWw9VFJVRSwgc2U9Ljk1LCBzcGFuPTEuMiwgYWxwaGE9LjQpIAoKcmYxIDwtIHJmc3JjKGRlYXRoc34gY29uZmlybWVkICsgdGVzdGVkX3Blb3BsZSwKICAgICAgICAgICAgICAgICAgICAgIGRhdGE9bGhzX2xvbmdfbWVkaWFuICU+JSBmaWx0ZXIoQ0ZSPDEpICU+JSBhcy5kYXRhLmZyYW1lKCkgKQpnZ19lIDwtIGdnX2Vycm9yKHJmMSkKZ2dfdiA8LSBnZ192YXJpYWJsZShyZjEpCnBsb3QoZ2dfdiwgcGFuZWw9VFJVRSwgc2U9Ljk1LCBzcGFuPTEuMiwgYWxwaGE9LjQpCgoKcmYyIDwtIHJmc3JjKENGUiB+ICB0ZXN0ZWRfcGVvcGxlX2xvZywKICAgICAgICAgICAgICAgICAgICAgIGRhdGE9bGhzX2xvbmdfbWVkaWFuICU+JSAKICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShDRlI9ZGVhdGhzL2NvbmZpcm1lZCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUodGVzdGVkX3Blb3BsZV9sb2c9bG9nKHRlc3RlZF9wZW9wbGUrMSkpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKENGUjwxKSAlPiUgYXMuZGF0YS5mcmFtZSgpCiAgICAgICAgICAgICApCmdnX3YgPC0gZ2dfdmFyaWFibGUocmYyKQpwbG90KGdnX3YsIHBhbmVsPVRSVUUsIHNlPS45NSwgc3Bhbj0xLjIsIGFscGhhPS40KQoKcmYyIDwtIHJmc3JjKENGUiB+ICB0ZXN0ZWRfcGVvcGxlX2xvZyArIGNvbmZpcm1lZF9sb2csCiAgICAgICAgICAgICAgICAgICAgICBkYXRhPWxoc19sb25nX21lZGlhbiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoQ0ZSPWRlYXRocy9jb25maXJtZWQpICU+JQogICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbG9nPWxvZyh0ZXN0ZWRfcGVvcGxlKzEpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nPWxvZyhjb25maXJtZWQrMSkpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKENGUjwxKSAlPiUgYXMuZGF0YS5mcmFtZSgpCiAgICAgICAgICAgICApCmdnX3YgPC0gZ2dfdmFyaWFibGUocmYyKQpwbG90KGdnX3YsIHBhbmVsPVRSVUUsIHNlPS45NSwgc3Bhbj0xLjIsIGFscGhhPS40KQoKCiNUaHJvdyBpbiB0aW1lCnJmMyA8LSByZnNyYyhDRlIgfiAgcG9zaXRpdmVfcGVyYyArIHRlc3RlZF9wZW9wbGVfbG9nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWxoc19sb25nX21lZGlhbiAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShDRlI9ZGVhdGhzL2NvbmZpcm1lZCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShwb3NpdGl2ZV9wZXJjPWNvbmZpcm1lZC90ZXN0ZWRfcGVvcGxlKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHRlc3RlZF9wZW9wbGVfbG9nPWxvZyh0ZXN0ZWRfcGVvcGxlKzEpKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2c9bG9nKGNvbmZpcm1lZCsxKSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihDRlI8MSkgJT4lIGFzLmRhdGEuZnJhbWUoKQogICAgICAgICAgICAgKQpnZ192IDwtIGdnX3ZhcmlhYmxlKHJmMykKcGxvdChnZ192LCBwYW5lbD1UUlVFLCBzZT0uOTUsIHNwYW49MS4yLCBhbHBoYT0uNCkKCnBhcnRpYWxfQm9zdG9uIDwtIHBsb3QudmFyaWFibGUocmYzLApwYXJ0aWFsPVRSVUUsIHNvcnRlZD1GQUxTRSwKc2hvdy5wbG90cyA9IEZBTFNFICkKCmdnX3AgPC0gZ2dfcGFydGlhbChwYXJ0aWFsX0Jvc3RvbikKcGxvdChnZ19wLCBwYW5lbD1UUlVFLCBwb2ludHMgPSBGICkKCgpjb3BwZXJfY3RzIDwtcXVhbnRpbGVfcHRzKGxoc19sb25nX21lZGlhbiR0ZXN0ZWRfcGVvcGxlX2xvZywgZ3JvdXBzID0gNiwgaW50ZXJ2YWxzID0gVFJVRSkKcGFydGlhbF9jb3Bsb3RfQm9zdG9uIDwtIGdnX3BhcnRpYWxfY29wbG90KHJmMiwgeHZhcj0iY29uZmlybWVkX2xvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBzPXJtX2dycCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93LnBsb3RzPUZBTFNFKQoKCgpzdW1tYXJ5KGxoc19sb25nX21lZGlhbiRDRlIpCgpsaHNfbG9uZ19tZWRpYW4gJT4lIGZpbHRlcihjb25maXJtZWQ+MTApICU+JSBmaWx0ZXIoQ0ZSPDEpICU+JSBwdWxsKENGUikgJT4lIHN1bW1hcnkoKSAjMC4wMjk3Mjk3ICB0aGF0J3MgYSBtZWRpYW4gQ0ZSIG9mIGFib3V0IDMlCmxoc19sb25nX21lZGlhbiAlPiUgZmlsdGVyKGNvbmZpcm1lZD4xMCkgJT4lIGZpbHRlcihDRlI8MSkgJT4lIHB1bGwoQ0ZSKSAlPiUgaGlzdChicmVha3M9NTApCgpsaHNfbG9uZ19tZWRpYW4gJT4lIGZpbHRlcihjb25maXJtZWQ+MTApICU+JSBmaWx0ZXIoQ0ZSPDEpICU+JSBnZ3Bsb3QoYWVzKHg9Q0ZSKSkgKyBnZW9tX2RlbnNpdHkoKQoKCmBgYAoKCgpgYGB7ciwgZXZhbD1GfQojVGhpcyBjb2RlIGlzIG5vdyBkZXByaWNhdGVkIGluIGZhdm9yIG9mIHRoZSB0cmVlIGJhc2UgbWV0aG9kIGFib3ZlCgpwbGFjZXMgPC0gbGhzX2xvbmdfY2xlYW4kd2lraWRhdGFfaWQgJT4lIHVuaXF1ZSgpICU+JSBuYS5vbWl0KCkgOyBsZW5ndGgocGxhY2VzKQpkYXRhc2V0cyA8LSBsaHNfbG9uZ19jbGVhbiRkYXRhc2V0ICU+JSB1bmlxdWUoKSAlPiUgbmEub21pdCgpIDsgdGFibGUoZGF0YXNldCkKCnRlbXBfbGlzdCA8LSBsaXN0KCkKZm9yKHAgaW4gcGxhY2VzKXsKICAgIHByaW50KHApCiAgICBmb3IoZCBpbiBkYXRhc2V0cyl7CiAgICAgIHRlbXAgPC0gTlVMTAogICAgICB0ZW1wIDwtIGxoc19sb25nX2NsZWFuICU+JSAKICAgICAgICAgICAgICBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKGRhdGFzZXQgJWluJSBkKSAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKHdpa2lkYXRhX2lkICVpbiUgcCkgJT4lIAogICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nPWxvZyhjb25maXJtZWQrMSkpICU+JQogICAgICAgICAgICAgIG11dGF0ZShkZWF0aHNfbG9nPWxvZyhkZWF0aHMrMSkpICU+JQogICAgICAgICAgICAgIG11dGF0ZSh0ZXN0ZWRfcGVvcGxlX2xvZz1sb2codGVzdGVkX3Blb3BsZSsxKSkgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHQ9IGFzLm51bWVyaWMoZGF0ZV9hc2RhdGUpIC0gbWluKGFzLm51bWVyaWMoZGF0ZV9hc2RhdGUpKSArMSAgKSAlPiUgI3N0YXJ0IGF0IDEgdG8gbWFrZSBpbmRleGluZyBlYXNpZXIKICAgICAgICAgICAgICBtdXRhdGUoaT0gcm93X251bWJlcigpICApICMgYWN0dWFsbHkgbmVlZCB0aGlzCiAgICAgICAgCiAgICAgIGlfb3JpZ2luYWwgPC0gdGVtcCRpCiAgICAgIAogICAgICBpZiggbnJvdyh0ZW1wKT09MCApIHsgbmV4dH0gI3ByaW50KCJlcnJvciIpOwogICAgICBwcmludChwKQogICAgICAKICAgICAgI2JwIDwtIGJyZWFrcG9pbnRzKGNvbmZpcm1lZF9sb2cgfiAxLCBkYXRhPXRlbXApCiAgICAgIGJwIDwtIE5VTEwKICAgICAgbG0xIDwtIE5VTEwKICAgICAgeV9oYXQgPC0gTkEKICAgICAgY2RmIDwtIE5VTEwKICAgICAgdHJ5KHsKICAgICAgICAgICAgI2lmIGl0IGZhaWxzIGZhbGwgYmFjayB0byBqdXN0IGEgbG0KICAgICAgICBsbTEgPC0gbG0oY29uZmlybWVkX2xvZyB+IDEgKyB0LCBkYXRhPXRlbXApCiAgICAKICAgICAgICBjZGYgPC0gZGF0YS5mcmFtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICB0PSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX2ludGVyY2VwdD0gY29lZihsbTEpWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpcm1lZF9sb2dfc2xvcGU9IGNvZWYobG0xKVsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX3Nsb3BlX2JyZWFrPTAKICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgY29uZmlybWVkX2xvZ195X2hhdD1maXR0ZWQudmFsdWVzKGxtMSkKICAgICAgfSkKICAgICAgCiAgICAgIHRyeSh7CiAgICAgICAgYnAgPC0gYnJlYWtwb2ludHMoY29uZmlybWVkX2xvZyB+IDEgKyB0LCBkYXRhPXRlbXAsIGg9MykKICAgICAgICAKICAgICAgICBjZGYgPC0gZGF0YS5mcmFtZSgKICAgICAgICAgICAgICAgICAgICAgICAgICBpPSBjKDEsYnAkYnJlYWtwb2ludHMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX2ludGVyY2VwdD0gY29lZihicClbLDFdLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpcm1lZF9sb2dfc2xvcGU9IGNvZWYoYnApWywyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb25maXJtZWRfbG9nX3Nsb3BlX2JyZWFrPTEKICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgY29uZmlybWVkX2xvZ195X2hhdD1maXR0ZWQudmFsdWVzKGJwKQogICAgICB9KQogICAgICAKICAgICAgdHJ5KHsKICAgICAgICB0ZW1wMiA8LSB0ZW1wCiAgICAgICAgdGVtcDIkY29uZmlybWVkX2xvZ195X2hhdCA8LSBOQQogICAgICAgIHRlbXAyJGNvbmZpcm1lZF9sb2dfeV9oYXQgPC0gY29uZmlybWVkX2xvZ195X2hhdAogICAgICAgIAogICAgICAgIHRlbXAyIDwtIHRlbXAyICU+JSAKICAgICAgICAgICAgICAgIGxlZnRfam9pbihjZGYpIAogICAgICAgIHE9cGFzdGUwKHAsIl8iLGQpCiAgICAgICAgdGVtcDIgPC0gdGVtcDIgJT4lIAogICAgICAgICAgICAgICAgICBleHBhbmQoZGF0YXNldCwgZ2lkLGdlb25hbWVpZCwgd2lraWRhdGFfaWQsdD1taW4odGVtcCR0KTptYXgodGVtcCR0KSkgJT4lICNleHBhbmQgdGhpcyB0byBpbmNsdWRlIGFsbCB0aGUgdCAKICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKHRlbXAyKSAlPiUgCiAgICAgICAgICAgICAgICAgIG11dGF0ZShkYXRlX2FzZGF0ZT1taW4oZGF0ZV9hc2RhdGUsIG5hLnJtPVQpLTErdCkgJT4lICNnbyBiYWNrIGludGVycCBkYXRlIGFnYWluCiAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nX3Nsb3BlX2JyZWFrID0gY29uZmlybWVkX2xvZ19zbG9wZV9icmVhayAlPiUgcmVwbGFjZV9uYSgwKSAlPiUgY3Vtc3VtKCkgKSAlPiUKICAgICAgICAgICAgICAgICAgZmlsbChjb25maXJtZWRfbG9nX2ludGVyY2VwdCkgJT4lCiAgICAgICAgICAgICAgICAgIGZpbGwoY29uZmlybWVkX2xvZ19zbG9wZSkgJT4lCiAgICAgICAgICAgICAgICAgIG11dGF0ZShjb25maXJtZWRfbG9nX3lfaGF0PSBjb25maXJtZWRfbG9nX2ludGVyY2VwdCArIGNvbmZpcm1lZF9sb2dfc2xvcGUqdCApICU+JSAKICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2dfc2xvcGVfcGVyY2VudF9jaGFuZ2UgPSByb3VuZCgoZXhwKGNvbmZpcm1lZF9sb2dfc2xvcGUpLTEpKjEwMCwyKSkgCgogICAgICAgIHRlbXBfbGlzdFtbYXMuY2hhcmFjdGVyKHEpXV0gPC0gdGVtcDIKICAgICAgfSkKICAgICAgI2lmKCBpcy5uYSggdGVtcF9saXN0W1thcy5jaGFyYWN0ZXIocSldXSR5X2hhdCkgKSB7cHJpbnQoImVycm9yIik7IGJyZWFrfQogICAgfQp9CiMiMTMwNTUiCnRlbXBfZGYgPC0gYmluZF9yb3dzKHRlbXBfbGlzdCkKZGltKHRlbXBfZGYpICNiaWdnZXIgYmVjYXVzZSB3ZSdyZSBpbnRlcnBvbGF0aW5nIG5vdwoKIyBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpCiNkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInRpZHl2ZXJzZS9tdWx0aWRwbHlyIikKCmxpYnJhcnkobXVsdGlkcGx5cikKbGlicmFyeShkcGx5ciwgd2Fybi5jb25mbGljdHMgPSBGQUxTRSkKI2NsdXN0ZXIgPC0gbmV3X2NsdXN0ZXIoNCkKCiNuZWVkIHRvIHN1cHJlc3MgbWVzc2FnZXMKcmV4X2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKHgpewogIHRlbXA9ZGF0YS5mcmFtZShjb25maXJtZWRfbG9nX3Nsb3BlPXgpCiAgdHJ5Q2F0Y2goewogICAgI2lmIHRoZXJlJ3MgYW4gTkEgaW4geCB3ZSBnZXQgYW4gZXJyb3IgYmVjYXVzZSBicmVha3BvaW50cyBpcyBvbmUgc2hvcnQKICAgIHByZWRpY3Rpb24gPC0gYnJlYWtwb2ludHMoZm9ybXVsYT1jb25maXJtZWRfbG9nX3Nsb3BlIH4gMSwgZGF0YT10ZW1wLCBoPTMpICU+JSBmaXR0ZWQudmFsdWVzKCkKICAgIHJlc3VsdD1yZXAoTkEsIGxlbmd0aCh4KSApCiAgICByZXN1bHRbIWlzLm5hKHgpXSA8LXByZWRpY3Rpb24KICAgIHJldHVybihyZXN1bHQpCiAgICAKICB9LCBlcnJvcj1mdW5jdGlvbihlKXt9KQogIAogIHJldHVybiggcmVwKE5BLCBsZW5ndGgoeCkgKSApCiAgICAgICAgIAp9CiNkaWRuJ3QgdGFrZSB0b28gbG9uZyBub3cKCiNsaWJyYXJ5KG11bHRpZHBseXIpCiNsaWJyYXJ5KGRwbHlyLCB3YXJuLmNvbmZsaWN0cyA9IEZBTFNFKQojY2x1c3RlciA8LSBuZXdfY2x1c3Rlcig0KQoKbGlicmFyeSh0aWN0b2MpCnRpYygpCmxpYnJhcnkoc3RydWNjaGFuZ2UpCnRlc3QgPC0gdGVtcF9kZiAlPiUgaGVhZCgyMDAwMCkKdGVzdDMgPC0gdGVzdCAlPiUgCiAgICAgICAgICAgICAgICBncm91cF9ieSh3aWtpZGF0YV9pZCkgJT4lIAogICAgICAgICAgICAgICAgI3BhcnRpdGlvbihjbHVzdGVyKSAlPiUKICAgICAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgICAgICAgI211dGF0ZSggY29uZmlybWVkX2xvZ19zbG9wZV95X2hhdCA9IGJyZWFrcG9pbnRzKGZvcm11bGE9Y29uZmlybWVkX2xvZ19zbG9wZSB+IDEsIGRhdGE9LiApICU+JSBmaXR0ZWQudmFsdWVzKCkgKSAlPiUgCiAgICAgICAgICAgICAgICBtdXRhdGUoIGNvbmZpcm1lZF9sb2dfc2xvcGVfeV9oYXQgPSByZXhfZnVuY3Rpb24oY29uZmlybWVkX2xvZ19zbG9wZSkgKSAlPiUgICNmYWlscyBvbiB0aGUgY2x1c3RlcgogICAgICAgICAgICAgICAgdW5ncm91cCgpICMlPiUKICAgICAgICAgICAgICAgICNjb2xsZWN0KCkKdG9jKCkgIzQ4IHNlY29uZHMgZm9yIDEwayAjMTIyIHNlY29uZHMgZm9yIDIwawoKc2F2ZVJEUyh0ZW1wX2RmLCAiL21lZGlhL3NreW5ldDIvOTA1ODg0ZjAtNzU0Ni00MjczLTkwNjEtMTJhNzkwODMwYmViL3J3ZF9naXRodWJfcHJpdmF0ZS9ORVNTY292aWQxOS9kYXRhX3RlbXAvbGhzX2xvbmdfaW50ZXJwb2xhdGVkLlJkcyIpCgpgYGAKCgoKCgoKCgoKYGBge3IsIGV2YWw9RiwgZWNobz1GLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRX0KCiNIZXJlIGlzIHdoZXJlIEkgd29ya2VkIG91dCB0aGUgaWRlYSBvZiBmaXR0aW5nIHBpZWNld2lzZSBsaW5lYXIgZnVuY3Rpb25zIHRvIGVhY2ggZGF0YXNldCBpbmRlcGVuZGVudGx5LiBJdCdzIG5vdyByZXBsYWNlZCB3aXRoIGEgZnVsbHkgYXV0b21hdGVkIHBpcGxpbmUgYmFzZWQgb24gdHJlZXMuCgpjb3VudF9kYXRhc2V0cyA8LSBsaHNfbG9uZ19jbGVhbiAlPiUgZHBseXI6OnNlbGVjdCh3aWtpZGF0YV9pZCwgZGF0YXNldCkgJT4lIGRpc3RpbmN0KCkgJT4lIGNvdW50KHdpa2lkYXRhX2lkKQoKZm9ybXVsYSA9IGNvbmZpcm1lZF9sb2cgfiAxICsgZGF0ZV9yYW5rICMrIEkoZGF0ZV9yYW5rXjIpICsgSShkYXRlX3JhbmteMykKaD01CiNiZXhhciBjb3VudHkKbGlicmFyeShzdHJ1Y2NoYW5nZSkgOyAjaW5zdGFsbC5wYWNrYWdlcygnc3RydWNjaGFuZ2UnKQp0ZW1wIDwtIGxoc19sb25nX2NsZWFuICU+JSBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkICVpbiUgIlExNjg2MSIpICU+JSAgbXV0YXRlKGNvbmZpcm1lZF9sb2c9bG9nKGNvbmZpcm1lZCsxKSkgJT4lCiAgICAgICAgbXV0YXRlKGRhdGVfcmFuaz0gYXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkgLSBtaW4oYXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkpKSAgCgp0YWJsZSh0ZW1wJGRhdGFzZXQpCgp0ZW1wX3VzYWZhY3RzIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0idXNhZmFjdHMiKQpicF91c2FmYWN0cyA8LSBicmVha3BvaW50cyhmb3JtdWxhLCBkYXRhPXRlbXBfdXNhZmFjdHMsaD1oKQp0ZW1wX3VzYWZhY3RzJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMoYnBfdXNhZmFjdHMpCnRlbXBfdXNhZmFjdHMkZ3JvdXBzIDwtIDA7IHRlbXBfdXNhZmFjdHMkZ3JvdXBzW2JwX3VzYWZhY3RzJGJyZWFrcG9pbnRzKzFdIDwtIDEgOyB0ZW1wX3VzYWZhY3RzJGdyb3VwcyA8LSBjdW1zdW0odGVtcF91c2FmYWN0cyRncm91cHMpKzEKCnRlbXBfbnl0IDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0ibnl0IikKYnBfbnl0IDwtIGJyZWFrcG9pbnRzKGZvcm11bGEsIGRhdGE9dGVtcF9ueXQsaD1oKQp0ZW1wX255dCR5X2hhdCA8LSBmaXR0ZWQudmFsdWVzKGJwX255dCkKdGVtcF9ueXQkZ3JvdXBzIDwtIDA7IHRlbXBfbnl0JGdyb3Vwc1ticF9ueXQkYnJlYWtwb2ludHMrMV0gPC0gMSA7IHRlbXBfbnl0JGdyb3VwcyA8LSBjdW1zdW0odGVtcF9ueXQkZ3JvdXBzKSsxCgoKdGVtcF9DU1NFIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iQ1NTRSIpCmJwX0NTU0UgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX0NTU0UsaD1oKQp0ZW1wX0NTU0UkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9DU1NFKQp0ZW1wX0NTU0UkZ3JvdXBzIDwtIDA7IHRlbXBfQ1NTRSRncm91cHNbYnBfQ1NTRSRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF9DU1NFJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9DU1NFJGdyb3VwcykrMQoKdGVtcF9iaW5nIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iYmluZyIpCmJwX2JpbmcgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX2JpbmcsaD1oKSAjdGhpcyBmYWlscyBiYyB0b28gZmV3CmxtX2JpbmcgPC1sbShmb3JtdWxhLCBkYXRhPXRlbXBfYmluZykKdGVtcF9iaW5nJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMobG1fYmluZykKdGVtcF9iaW5nJGdyb3VwcyA8LTEKCnRlbXBfZGYgPC0gYmluZF9yb3dzKHRlbXBfbnl0LCB0ZW1wX0NTU0UsIHRlbXBfYmluZywgdGVtcF91c2FmYWN0cykgICU+JSAKICAgICAgICAgICAgYXJyYW5nZShkYXRhc2V0LGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgICAgbXV0YXRlKGdyb3Vwcz1wYXN0ZShkYXRhc2V0LGdyb3VwcykpCgp0ZW1wX2RmMiA8LSBiaW5kX3Jvd3ModGVtcF9ueXQsIHRlbXBfQ1NTRSwgdGVtcF9iaW5nLCB0ZW1wX3VzYWZhY3RzKSAlPiUgCiAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICAgZ3JvdXBfYnkoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZSh5X2hhdF9tZWFuPW1lYW4oeV9oYXQsIG5hLnJtPVQpKSAlPiUKICAgICAgICAgICAgbXV0YXRlKGdyb3Vwcz05OSkKCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSkgKwogICBnZW9tX2xpbmUoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXBzKSkgKwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJCZXhhciBDb3VudHkgKFExNjg2MSkgQ29uZmlybWVkIikKCgoKIyMjIyMKI0NoaW5hIFExNDgKdGVtcCA8LSBsaHNfbG9uZ19jbGVhbiAlPiUgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lIAogICAgICAgIGZpbHRlcih3aWtpZGF0YV9pZCAlaW4lICJRMTQ4IikgJT4lIAogICAgICAgIGdyb3VwX2J5KGRhdGFzZXQsIGRhdGVfYXNkYXRlKSAlPiUKICAgICAgICAgIHN1bW1hcmlzZShjb25maXJtZWQ9bWF4KGNvbmZpcm1lZCwgbmEucm09VCkgKSAlPiUgI3RoaXMgaXMgYSBwcm9ibGVtIGR1cGVzIHdpdGggdGhlIHNhbWUgZGF0ZSAgI3RoaXMgZml4ZXMgYSBsb3Qgb2YgdGhpbmdzIGJ1dCB3ZSBuZWVkIHRvIGZpZ3VyZSBvdXQgdGhlIG9yaWdpbiBvZiB0aGlzIHByb2JsZW0KICAgICAgICB1bmdyb3VwKCkgJT4lCiAgICAgICAgbXV0YXRlKGNvbmZpcm1lZF9sb2c9bG9nKGNvbmZpcm1lZCsxKSkgJT4lIAogICAgICAgIG11dGF0ZShkYXRlX3Jhbms9IGFzLm51bWVyaWMoZGF0ZV9hc2RhdGUpIC0gbWluKGFzLm51bWVyaWMoZGF0ZV9hc2RhdGUpKSkgIAoKCnRlbXBfd2lraXBlZGlhIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0id2lraXBlZGlhIikKYnBfd2lraXBlZGlhIDwtIGJyZWFrcG9pbnRzKGZvcm11bGEsIGRhdGE9dGVtcF93aWtpcGVkaWEsaD1oKQp0ZW1wX3dpa2lwZWRpYSR5X2hhdCA8LSBmaXR0ZWQudmFsdWVzKGJwX3dpa2lwZWRpYSkKdGVtcF93aWtpcGVkaWEkZ3JvdXBzIDwtIDA7IHRlbXBfd2lraXBlZGlhJGdyb3Vwc1ticF93aWtpcGVkaWEkYnJlYWtwb2ludHMrMV0gPC0gMSA7IHRlbXBfd2lraXBlZGlhJGdyb3VwcyA8LSBjdW1zdW0odGVtcF93aWtpcGVkaWEkZ3JvdXBzKSsxCgoKdGVtcF9lY2RjIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iZWNkYyIpCmJwX2VjZGMgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX2VjZGMsaD1oKQp0ZW1wX2VjZGMkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9lY2RjKQp0ZW1wX2VjZGMkZ3JvdXBzIDwtIDA7IHRlbXBfZWNkYyRncm91cHNbYnBfZWNkYyRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF9lY2RjJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9lY2RjJGdyb3VwcykrMQoKdGVtcF93aG8gPC0gdGVtcCAlPiUgZmlsdGVyKGRhdGFzZXQ9PSJ3aG8iKQpicF93aG8gPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX3dobyxoPWgpCnRlbXBfd2hvJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMoYnBfd2hvKQp0ZW1wX3dobyRncm91cHMgPC0gMDsgdGVtcF93aG8kZ3JvdXBzW2JwX3dobyRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF93aG8kZ3JvdXBzIDwtIGN1bXN1bSh0ZW1wX3dobyRncm91cHMpKzEKCgp0ZW1wX21ldGFiaW90YSA8LSB0ZW1wICU+JSBmaWx0ZXIoZGF0YXNldD09Im1ldGFiaW90YSIpCmJwX21ldGFiaW90YSA8LSBicmVha3BvaW50cyhmb3JtdWxhLCBkYXRhPXRlbXBfbWV0YWJpb3RhLGg9aCkKdGVtcF9tZXRhYmlvdGEkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9tZXRhYmlvdGEpCnRlbXBfbWV0YWJpb3RhJGdyb3VwcyA8LSAwOyB0ZW1wX21ldGFiaW90YSRncm91cHNbYnBfbWV0YWJpb3RhJGJyZWFrcG9pbnRzKzFdIDwtIDEgOyB0ZW1wX21ldGFiaW90YSRncm91cHMgPC0gY3Vtc3VtKHRlbXBfbWV0YWJpb3RhJGdyb3VwcykrMQoKdGVtcF9iaW5nIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iYmluZyIpCmJwX2JpbmcgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX2JpbmcsaD1oKSAjdGhpcyBmYWlscyBiYyB0b28gZmV3CmxtX2JpbmcgPC1sbShmb3JtdWxhLCBkYXRhPXRlbXBfYmluZykKdGVtcF9iaW5nJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMobG1fYmluZykKdGVtcF9iaW5nJGdyb3VwcyA8LTEKCnRlbXBfZGYgPC0gYmluZF9yb3dzKHRlbXBfZWNkYywgdGVtcF9tZXRhYmlvdGEsIHRlbXBfYmluZywgdGVtcF93aG8sIHRlbXBfd2lraXBlZGlhKSAlPiUgCiAgICAgICAgICAgIGFycmFuZ2UoZGF0YXNldCxkYXRlX2FzZGF0ZSkgJT4lIAogICAgICAgICAgIG11dGF0ZShncm91cHM9cGFzdGUoZGF0YXNldCxncm91cHMpKQoKdGVtcF9kZjIgPC0gYmluZF9yb3dzKHRlbXBfZWNkYywgdGVtcF9tZXRhYmlvdGEsIHRlbXBfYmluZywgdGVtcF93aG8sIHRlbXBfd2lraXBlZGlhKSAlPiUgCiAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICAgZ3JvdXBfYnkoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZSh5X2hhdF9tZWFuPW1lYW4oeV9oYXQsIG5hLnJtPVQpKSAlPiUKICAgICAgICAgICAgbXV0YXRlKGdyb3Vwcz05OSkKCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSkgKwogICBnZW9tX2xpbmUoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXBzKSkgKwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJDaGluYSAoUTE0OCkgQ29uZmlybWVkIikKICAgI2dlb21fdmxpbmUoeGludGVyY2VwdD1icCRicmVha3BvaW50cykKCgojSW5kaWEKIyJRNjY4Igp0ZW1wIDwtIGxoc19sb25nX2NsZWFuICU+JSBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgZmlsdGVyKHdpa2lkYXRhX2lkICVpbiUgIlE2NjgiKSAlPiUgCiAgICAgICAgZ3JvdXBfYnkoZGF0YXNldCwgZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgc3VtbWFyaXNlKGNvbmZpcm1lZD1tYXgoY29uZmlybWVkLCBuYS5ybT1UKSApICU+JSAjdGhpcyBpcyBhIHByb2JsZW0gZHVwZXMgd2l0aCB0aGUgc2FtZSBkYXRlICAjdGhpcyBmaXhlcyBhIGxvdCBvZiB0aGluZ3MgYnV0IHdlIG5lZWQgdG8gZmlndXJlIG91dCB0aGUgb3JpZ2luIG9mIHRoaXMgcHJvYmxlbQogICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICBtdXRhdGUoY29uZmlybWVkX2xvZz1sb2coY29uZmlybWVkKzEpKSAlPiUgCiAgICAgICAgbXV0YXRlKGRhdGVfcmFuaz0gYXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkgLSBtaW4oYXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkpKSAgCnRhYmxlKHRlbXAkZGF0YXNldCkKCnRlbXBfY292aWQxOWluZGlhIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iY292aWQxOWluZGlhIikKYnBfY292aWQxOWluZGlhIDwtIGJyZWFrcG9pbnRzKGZvcm11bGEsIGRhdGE9dGVtcF9jb3ZpZDE5aW5kaWEsaD1oKQp0ZW1wX2NvdmlkMTlpbmRpYSR5X2hhdCA8LSBmaXR0ZWQudmFsdWVzKGJwX2NvdmlkMTlpbmRpYSkKdGVtcF9jb3ZpZDE5aW5kaWEkZ3JvdXBzIDwtIDA7IHRlbXBfY292aWQxOWluZGlhJGdyb3Vwc1ticF9jb3ZpZDE5aW5kaWEkYnJlYWtwb2ludHMrMV0gPC0gMSA7IHRlbXBfY292aWQxOWluZGlhJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9jb3ZpZDE5aW5kaWEkZ3JvdXBzKSsxCgp0ZW1wX3dpa2lwZWRpYSA8LSB0ZW1wICU+JSBmaWx0ZXIoZGF0YXNldD09Indpa2lwZWRpYSIpCmJwX3dpa2lwZWRpYSA8LSBicmVha3BvaW50cyhmb3JtdWxhLCBkYXRhPXRlbXBfd2lraXBlZGlhLGg9aCkKdGVtcF93aWtpcGVkaWEkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF93aWtpcGVkaWEpCnRlbXBfd2lraXBlZGlhJGdyb3VwcyA8LSAwOyB0ZW1wX3dpa2lwZWRpYSRncm91cHNbYnBfd2lraXBlZGlhJGJyZWFrcG9pbnRzKzFdIDwtIDEgOyB0ZW1wX3dpa2lwZWRpYSRncm91cHMgPC0gY3Vtc3VtKHRlbXBfd2lraXBlZGlhJGdyb3VwcykrMQoKdGVtcF9DU1NFIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iQ1NTRSIpCmJwX0NTU0UgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX0NTU0UsaD1oKQp0ZW1wX0NTU0UkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9DU1NFKQp0ZW1wX0NTU0UkZ3JvdXBzIDwtIDA7IHRlbXBfQ1NTRSRncm91cHNbYnBfQ1NTRSRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF9DU1NFJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9DU1NFJGdyb3VwcykrMQoKdGVtcF9lY2RjIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iZWNkYyIpCmJwX2VjZGMgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX2VjZGMsaD1oKQp0ZW1wX2VjZGMkeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9lY2RjKQp0ZW1wX2VjZGMkZ3JvdXBzIDwtIDA7IHRlbXBfZWNkYyRncm91cHNbYnBfZWNkYyRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF9lY2RjJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9lY2RjJGdyb3VwcykrMQoKdGVtcF93aG8gPC0gdGVtcCAlPiUgZmlsdGVyKGRhdGFzZXQ9PSJ3aG8iKQpicF93aG8gPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX3dobyxoPWgpCnRlbXBfd2hvJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMoYnBfd2hvKQp0ZW1wX3dobyRncm91cHMgPC0gMDsgdGVtcF93aG8kZ3JvdXBzW2JwX3dobyRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF93aG8kZ3JvdXBzIDwtIGN1bXN1bSh0ZW1wX3dobyRncm91cHMpKzEKCnRlbXBfbWV0YWJpb3RhIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0ibWV0YWJpb3RhIikKYnBfbWV0YWJpb3RhIDwtIGJyZWFrcG9pbnRzKGZvcm11bGEsIGRhdGE9dGVtcF9tZXRhYmlvdGEsaD1oKQp0ZW1wX21ldGFiaW90YSR5X2hhdCA8LSBmaXR0ZWQudmFsdWVzKGJwX21ldGFiaW90YSkKdGVtcF9tZXRhYmlvdGEkZ3JvdXBzIDwtIDA7IHRlbXBfbWV0YWJpb3RhJGdyb3Vwc1ticF9tZXRhYmlvdGEkYnJlYWtwb2ludHMrMV0gPC0gMSA7IHRlbXBfbWV0YWJpb3RhJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9tZXRhYmlvdGEkZ3JvdXBzKSsxCgp0ZW1wX2JpbmcgPC0gdGVtcCAlPiUgZmlsdGVyKGRhdGFzZXQ9PSJiaW5nIikKYnBfYmluZyA8LSBicmVha3BvaW50cyhmb3JtdWxhLCBkYXRhPXRlbXBfYmluZyxoPWgpICN0aGlzIGZhaWxzIGJjIHRvbyBmZXcKbG1fYmluZyA8LWxtKGZvcm11bGEsIGRhdGE9dGVtcF9iaW5nKQp0ZW1wX2JpbmckeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhsbV9iaW5nKQp0ZW1wX2JpbmckZ3JvdXBzIDwtMQoKdGVtcF9kZiA8LSBiaW5kX3Jvd3ModGVtcF9jb3ZpZDE5aW5kaWEsIHRlbXBfd2lraXBlZGlhLCB0ZW1wX0NTU0UsIHRlbXBfZWNkYywgdGVtcF93aG8sIHRlbXBfbWV0YWJpb3RhLCB0ZW1wX2JpbmcpICU+JSAKICAgICAgICAgICAgYXJyYW5nZShkYXRhc2V0LGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgICAgbXV0YXRlKGdyb3Vwcz1wYXN0ZShkYXRhc2V0LGdyb3VwcykpCgp0ZW1wX2RmMiA8LSBiaW5kX3Jvd3ModGVtcF9jb3ZpZDE5aW5kaWEsIHRlbXBfd2lraXBlZGlhLCB0ZW1wX0NTU0UsIHRlbXBfZWNkYywgdGVtcF93aG8sIHRlbXBfbWV0YWJpb3RhLCB0ZW1wX2JpbmcpICU+JSAKICAgICAgICAgICAgYXJyYW5nZShkYXRlX2FzZGF0ZSkgJT4lIAogICAgICAgICAgICBncm91cF9ieShkYXRlX2FzZGF0ZSkgJT4lCiAgICAgICAgICAgICAgc3VtbWFyaXNlKHlfaGF0X21lYW49bWVhbih5X2hhdCwgbmEucm09VCkpICU+JQogICAgICAgICAgICBtdXRhdGUoZ3JvdXBzPTk5KQoKZ2dwbG90KCkgKyAKICAgZ2VvbV9wb2ludChkYXRhPXRlbXBfZGYsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PWNvbmZpcm1lZF9sb2csIGNvbG9yPWRhdGFzZXQpLCBhbHBoYT0uMykgKwogICBnZW9tX2xpbmUoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdCwgY29sb3I9ZGF0YXNldCwgZ3JvdXA9Z3JvdXBzKSkgKwogICAjZ2VvbV9saW5lKGRhdGE9dGVtcF9kZjIsIGFlcyh4PWRhdGVfYXNkYXRlLCB5PXlfaGF0X21lYW4pLCBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgIHRoZW1lX2J3KCkgKwogICBnZ3RpdGxlKCJJbmRpYSAoUTY2OCkgQ29uZmlybWVkIikKCgojRmxvcmlkYQojUTgxMgp0ZW1wIDwtIGxoc19sb25nX2NsZWFuICU+JSBhcnJhbmdlKGRhdGVfYXNkYXRlKSAlPiUgCiAgICAgICAgZmlsdGVyKHdpa2lkYXRhX2lkICVpbiUgIlE4MTIiKSAlPiUgCiAgICAgICAgZ3JvdXBfYnkoZGF0YXNldCwgZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgc3VtbWFyaXNlKGNvbmZpcm1lZD1tYXgoY29uZmlybWVkLCBuYS5ybT1UKSApICU+JSAjdGhpcyBpcyBhIHByb2JsZW0gZHVwZXMgd2l0aCB0aGUgc2FtZSBkYXRlICAjdGhpcyBmaXhlcyBhIGxvdCBvZiB0aGluZ3MgYnV0IHdlIG5lZWQgdG8gZmlndXJlIG91dCB0aGUgb3JpZ2luIG9mIHRoaXMgcHJvYmxlbQogICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICBtdXRhdGUoY29uZmlybWVkX2xvZz1sb2coY29uZmlybWVkKzEpKSAlPiUKICAgICAgICBtdXRhdGUoZGF0ZV9yYW5rPSBhcy5udW1lcmljKGRhdGVfYXNkYXRlKSAtIG1pbihhcy5udW1lcmljKGRhdGVfYXNkYXRlKSkpICAKdGFibGUodGVtcCRkYXRhc2V0KQoKdGVtcF9jb3ZpZHRyYWNraW5nIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0iY292aWR0cmFja2luZyIpCmJwX2NvdmlkdHJhY2tpbmcgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX2NvdmlkdHJhY2tpbmcsaD1oKQp0ZW1wX2NvdmlkdHJhY2tpbmckeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhicF9jb3ZpZHRyYWNraW5nKQp0ZW1wX2NvdmlkdHJhY2tpbmckZ3JvdXBzIDwtIDA7IHRlbXBfY292aWR0cmFja2luZyRncm91cHNbYnBfY292aWR0cmFja2luZyRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF9jb3ZpZHRyYWNraW5nJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9jb3ZpZHRyYWNraW5nJGdyb3VwcykrMQoKdGVtcF93aWtpcGVkaWEgPC0gdGVtcCAlPiUgZmlsdGVyKGRhdGFzZXQ9PSJ3aWtpcGVkaWEiKQpicF93aWtpcGVkaWEgPC0gYnJlYWtwb2ludHMoZm9ybXVsYSwgZGF0YT10ZW1wX3dpa2lwZWRpYSxoPWgpCnRlbXBfd2lraXBlZGlhJHlfaGF0IDwtIGZpdHRlZC52YWx1ZXMoYnBfd2lraXBlZGlhKQp0ZW1wX3dpa2lwZWRpYSRncm91cHMgPC0gMDsgdGVtcF93aWtpcGVkaWEkZ3JvdXBzW2JwX3dpa2lwZWRpYSRicmVha3BvaW50cysxXSA8LSAxIDsgdGVtcF93aWtpcGVkaWEkZ3JvdXBzIDwtIGN1bXN1bSh0ZW1wX3dpa2lwZWRpYSRncm91cHMpKzEKCnRlbXBfbWV0YWJpb3RhIDwtIHRlbXAgJT4lIGZpbHRlcihkYXRhc2V0PT0ibWV0YWJpb3RhIikKYnBfbWV0YWJpb3RhIDwtIGJyZWFrcG9pbnRzKGZvcm11bGEsIGRhdGE9dGVtcF9tZXRhYmlvdGEsaD1oKQp0ZW1wX21ldGFiaW90YSR5X2hhdCA8LSBmaXR0ZWQudmFsdWVzKGJwX21ldGFiaW90YSkKdGVtcF9tZXRhYmlvdGEkZ3JvdXBzIDwtIDA7IHRlbXBfbWV0YWJpb3RhJGdyb3Vwc1ticF9tZXRhYmlvdGEkYnJlYWtwb2ludHMrMV0gPC0gMSA7IHRlbXBfbWV0YWJpb3RhJGdyb3VwcyA8LSBjdW1zdW0odGVtcF9tZXRhYmlvdGEkZ3JvdXBzKSsxCgp0ZW1wX2JpbmcgPC0gdGVtcCAlPiUgZmlsdGVyKGRhdGFzZXQ9PSJiaW5nIikKYnBfYmluZyA8LSBicmVha3BvaW50cyhmb3JtdWxhLCBkYXRhPXRlbXBfYmluZyxoPWgpICN0aGlzIGZhaWxzIGJjIHRvbyBmZXcKbG1fYmluZyA8LWxtKGZvcm11bGEsIGRhdGE9dGVtcF9iaW5nKQp0ZW1wX2JpbmckeV9oYXQgPC0gZml0dGVkLnZhbHVlcyhsbV9iaW5nKQp0ZW1wX2JpbmckZ3JvdXBzIDwtMQoKdGVtcF9kZiA8LSBiaW5kX3Jvd3ModGVtcF9jb3ZpZHRyYWNraW5nLCB0ZW1wX3dpa2lwZWRpYSwgdGVtcF9tZXRhYmlvdGEsIHRlbXBfYmluZykgJT4lIAogICAgICAgICAgICBhcnJhbmdlKGRhdGFzZXQsZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICBtdXRhdGUoZ3JvdXBzPXBhc3RlKGRhdGFzZXQsZ3JvdXBzKSkKCnRlbXBfZGYyIDwtIGJpbmRfcm93cyh0ZW1wX2NvdmlkdHJhY2tpbmcsIHRlbXBfd2lraXBlZGlhLCB0ZW1wX21ldGFiaW90YSwgdGVtcF9iaW5nKSAlPiUgCiAgICAgICAgICAgIGFycmFuZ2UoZGF0ZV9hc2RhdGUpICU+JSAKICAgICAgICAgICAgZ3JvdXBfYnkoZGF0ZV9hc2RhdGUpICU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZSh5X2hhdF9tZWFuPW1lYW4oeV9oYXQsIG5hLnJtPVQpKSAlPiUKICAgICAgICAgICAgbXV0YXRlKGdyb3Vwcz05OSkKCmdncGxvdCgpICsgCiAgIGdlb21fcG9pbnQoZGF0YT10ZW1wX2RmLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT1jb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjMpICsKICAgZ2VvbV9saW5lKGRhdGE9dGVtcF9kZiwgYWVzKHg9ZGF0ZV9hc2RhdGUsIHk9eV9oYXQsIGNvbG9yPWRhdGFzZXQsIGdyb3VwPWdyb3VwcykpICsKICAgI2dlb21fbGluZShkYXRhPXRlbXBfZGYyLCBhZXMoeD1kYXRlX2FzZGF0ZSwgeT15X2hhdF9tZWFuKSwgY29sb3I9ImJsYWNrIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICB0aGVtZV9idygpICsKICAgZ2d0aXRsZSgiRmxvcmlkYSAoUTgxMikgQ29uZmlybWVkIikKCmBgYAoKCgpgYGB7ciwgZXZhbD1GLCBlY2hvPUYsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFfQojQXMgd2FzIHRoaXMgcGFydAojICMgUTY2OCAgUTE2ODYxICBRMTQ4ICBRMzAgUTE0OCBRMTY4NjEgUTMwCnRlbXAgPC0gdGVtcF9kZiAlPiUgZmlsdGVyKHdpa2lkYXRhX2lkPT0iUTE0OCIpICU+JSBtdXRhdGUoZGF0ZV9hc251bWVyaWM9YXMubnVtZXJpYyhkYXRlX2FzZGF0ZSkpCnRlbXAgJT4lIGdncGxvdCgpICsgZ2VvbV9wb2ludChhZXMoZGF0ZV9hc2RhdGUsY29uZmlybWVkX2xvZykpICArIGZhY2V0X3dyYXAofmRhdGFzZXQpICMrIGdlb21fcG9pbnQoYWVzKGRhdGVfYXNkYXRlLGNvbmZpcm1lZF9sb2dfeV9oYXQpLCBjb2xvcj0iYmx1ZSIpCgojbGlicmFyeShycGFydCkKI3J0IDwtIHJwYXJ0KGNvbmZpcm1lZF9sb2cgfiAxICsgZGF0ZV9hc2RhdGUgLCBkYXRhPXRlbXApCiN0ZW1wJHlfaGF0IDwtIHByZWRpY3QoIHJ0LCBuZXdkYXRhPXRlbXAgKQoKI3RlbXAkZGF0YXNldCA8LSBhcy5mYWN0b3IodGVtcCRkYXRhc2V0KQojZm1CSCA8LSBtb2IoY29uZmlybWVkX2xvZyB+IDEgKyB0ICsgSSh0XjIpICsgSSh0XjMpIHwgdCArIGRhdGFzZXQsIGNvbnRyb2wgPSBtb2JfY29udHJvbChtaW5zcGxpdCA9IDMpLCBkYXRhID0gdGVtcCwgIG1vZGVsID0gbGluZWFyTW9kZWwpICN0aGlzIGZpdHMgYSBwaWVjZXdpc2UgbGluZWFyIHRvIGVhY2ggZGF0YXNldCAjaGF2ZSB0byB1c2UgdCwgZG9lc24ndCBsaWtlIGRhdGEgb2JqZWN0cwojcGxvdChmbUJIKQojY29lZihmbUJIKQojdGVtcCR5X2hhdCA8LSBwcmVkaWN0KCBmbUJILCBuZXdkYXRhPXRlbXAgKQoKI1RoZSB0cmljayBpcyBmaXR0aW5nIG9ubHkgdG8gb25lIGRhdGFzZXQgYXQgYSB0aW1lCnRlbXBfbGlzdCA8LSBsaXN0KCkKZm9yKCBkIGluIHRlbXAkZGF0YXNldCAlPiUgdW5pcXVlKCkgKXsKICB0ZW1wdGVtcCA8LSB0ZW1wICU+JSBmaWx0ZXIoZGF0YXNldD09ZCkKICBmbUJIIDwtIG1vYihjb25maXJtZWRfbG9nIH4gMSArIGRhdGVfYXNudW1lcmljICAgIHwgZGF0ZV9hc251bWVyaWMgLCBjb250cm9sID0gbW9iX2NvbnRyb2wobWluc3BsaXQgPSAzLCBhbHBoYT0uMiksIGRhdGEgPSB0ZW1wdGVtcCwgIG1vZGVsID0gbGluZWFyTW9kZWwpICAjICsgSShkYXRlX2FzbnVtZXJpY14yKSAgICAgKyBJKHReMykgICMgKyBJKHReMikgKyBJKHReMykgKyBJKHReNCkgKyBJKHReMikgCiAgdGVtcHRlbXAkeV9oYXQgPC0gcHJlZGljdCggZm1CSCwgbmV3ZGF0YT10ZW1wdGVtcCAsIHR5cGUgPSBjKCJyZXNwb25zZSIpICkKICB0ZW1wdGVtcCRncm91cF9udW1iZXIgPC0gIHByZWRpY3QoIGZtQkgsIG5ld2RhdGE9dGVtcHRlbXAgLCB0eXBlID0gYygibm9kZSIpKQogIHRlbXB0ZW1wIDwtIHRlbXB0ZW1wICU+JSBncm91cF9ieShncm91cF9udW1iZXIpICU+JSBhcnJhbmdlKGRhdGVfYXNudW1lcmljKSAlPiUgbXV0YXRlKHNsb3BlPXRzaWJibGU6OmRpZmZlcmVuY2UoeV9oYXQpKSAlPiUgZmlsbChzbG9wZSwgLmRpcmVjdGlvbj0idXAiKSAlPiUgdW5ncm91cCgpICU+JQogICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHBlcmNlbnRfY2hhbmdlID0gcm91bmQoKGV4cChzbG9wZSktMSkqMTAwLDIpKSAKCiAgdGVtcF9saXN0W1tkXV0gPC0gdGVtcHRlbXAKfQoKY29tYmluZWQgPC0gYmluZF9yb3dzKHRlbXBfbGlzdCkgCnAwIDwtIGNvbWJpbmVkICU+JQogICAgIG11dGF0ZShncm91cD1wYXN0ZSh3aWtpZGF0YV9pZCwgZGF0YXNldCwgZ3JvdXBfbnVtYmVyKSkgJT4lCiAgICAgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyhkYXRlX2FzZGF0ZSxjb25maXJtZWRfbG9nLCBjb2xvcj1kYXRhc2V0KSwgYWxwaGE9LjUpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShhZXMoZGF0ZV9hc2RhdGUseV9oYXQsIGdyb3VwPWdyb3VwKSwgY29sb3I9ImJsdWUiLCBhbHBoYT0xKSArIGZhY2V0X3dyYXAofmRhdGFzZXQpICsgdGhlbWVfYncoKSAjaXQgc2hpdHMgdGhlIGJlZCBpbiB0aGF0IGJpZyBnYXAgaW4gd2lraXBlZGlhCgpmbUJIX3Nsb3BlIDwtIG1vYihjb25maXJtZWRfbG9nIH4gMSAgIHwgZGF0ZV9hc251bWVyaWMgLCBjb250cm9sID0gbW9iX2NvbnRyb2wobWluc3BsaXQgPSAzLCBhbHBoYT0uMSksIGRhdGEgPSBjb21iaW5lZCwgIG1vZGVsID0gbGluZWFyTW9kZWwpICAjaXQgZG9lc24ndCB3YW50IHRvIGRvIApydDEgPC0gcnBhcnQoZm9ybXVsYSA9IHBlcmNlbnRfY2hhbmdlIH4gZGF0ZV9hc251bWVyaWMsIGRhdGE9Y29tYmluZWQpCmNvbWJpbmVkJHBlcmNlbnRfY2hhbmdlX3lfaGF0IDwtICBwcmVkaWN0KHJ0MSwgbmV3ZGF0YT1jb21iaW5lZCkKI2NvbWJpbmVkJHNsb3BlX3lfaGF0IDwtIHByZWRpY3QoIGZtQkhfc2xvcGUsIG5ld2RhdGE9Y29tYmluZWQgICwgdHlwZSA9IGMoInJlc3BvbnNlIikgKQojY29tYmluZWQkZ3JvdXBfbnVtYmVyIDwtIHByZWRpY3QoIGZtQkhfc2xvcGUsIG5ld2RhdGE9Y29tYmluZWQgICwgdHlwZSA9IGMoIm5vZGUiKSApCgpwMSA8LSBjb21iaW5lZCAlPiUKICAgICBtdXRhdGUoZ3JvdXA9cGFzdGUod2lraWRhdGFfaWQsIGRhdGFzZXQsIGdyb3VwX251bWJlcikpICU+JQogICAgIGdncGxvdCgpICsgZ2VvbV9wb2ludChhZXMoZGF0ZV9hc2RhdGUsY29uZmlybWVkX2xvZywgY29sb3I9ZGF0YXNldCksIGFscGhhPS41KSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoYWVzKGRhdGVfYXNkYXRlLHlfaGF0LCBncm91cD1ncm91cCwgY29sb3I9ZGF0YXNldCksIGFscGhhPS4xKSArIHRoZW1lX2J3KCkgKyBmYWNldF93cmFwKH5kYXRhc2V0KSMgICNpdCBzaGl0cyB0aGUgYmVkIGluIHRoYXQgYmlnIGdhcCBpbiB3aWtpcGVkaWEKCgpwMiA8LSBjb21iaW5lZCAlPiUgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyhkYXRlX2FzZGF0ZSxwZXJjZW50X2NoYW5nZV95X2hhdCwgY29sb3I9ZGF0YXNldCksIGFscGhhPS41KSArIAogICAgICAgICAgICAgZ2VvbV9saW5lKGFlcyhkYXRlX2FzZGF0ZSxwZXJjZW50X2NoYW5nZV95X2hhdCksIGNvbG9yPSJibGFjayIsIGFscGhhPTEpICsgdGhlbWVfYncoKSArIGZhY2V0X3dyYXAofmRhdGFzZXQpICMrIGZhY2V0X3dyYXAofmRhdGFzZXQpICNpdCBzaGl0cyB0aGUgYmVkIGluIHRoYXQgYmlnIGdhcCBpbiB3aWtpcGVkaWEKCnAxIC8gcDIKCgpgYGAKCgo=